📚위치에 따른 기억 클래스

기억 클래스는 변수를 기억공간의 특정 영역에 할당하는 방법이다. C 언어에서 모든 변수는 자료형과 기억 클래스를 갖는다. 기억 클래스는 변수가 어디에 사용될 것인지 또는 언제까지 존재할 것인지 또 어떻게 초기화 될 것인지를 결정한다. 변수의 사용 위치에 따라 지역변수와 전역변수, 변수의 존속 기간에 따라 자동변수, 정적변수, 외부변수, 레지스터 변수로 구별한다.


📄전역변수

전역변수는 함수 밖이나 외부 파일에서 선언되어 프로그램 전체에 걸쳐 사용될 수 있는 변수를 말한다. 같은 범위 안에 동일한 이름의 지역변수와 전역변수가 있을 때 지역변수가 우선한다. 전역변수는 가급적 꼭 필요한 경우에만 사용하는 것이 좋다. 전역변수를 사용하면 변수값의 변화에 따른 실행 결과를 살펴보기 어려워지기 때문이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

void func1();

int x;                      // 전역변수, 초기화하지 않으면 0으로 자동 초기화

void main()
{
  printf("x = %d \n", x);
  func1();
  printf("x = %d \n", x);
}

void func1()
{
  ++x;
}


📄지역변수

지역변수는 특정 범위 내에서만 통용되는 변수이다. 즉, 선언된 블록이나 함수 내에서만 사용이 가능하다. 함수의 매개변수도 지역 변수의 특성을 가진다. 프로그램 작성 시 되도록이면 전역변수보다 지역변수를 사용하는 것이 좋은데 전역변수에 비해 지역변수를 사용하는데 있어 장점은 아래와 같다.

  • 코드의 재활용이 쉬워짐
  • 효율적인 기억공간 사용 가능
  • 재귀함수 구현은 지역변수만 가능
  • 전역변수는 에러 수정을 어렵게 만든다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

void func1();

void main()
{
  int i = 10;                       // main() 함수 내부에 선언된 지역변수

  printf("main i = %d \n", i);
}

void func1()
{
  int i = 1;                        // func1() 함수 내부에 선언된 지역변수

  printf("func1 i = %d \n", i);
}



📚변수 존속 기간에 따른 기억 클래스

📄자동변수

자동변수는 함수 실행 시 만들어지고 실행이 끝나면 기억공간이 제거된다. auto라는 예약어를 사용하며 생략이 가능하다. 자동변수는 변수가 선언된 블록 안이나 함수 내로 한정된다. 보통 지역변수를 선언할 때 auto를 생략한다. 자동변수는 스택이라는 기억공간에 공간이 확보되고 함수 실행이 끝나면 기억공간에서 사라진다. 자동변수는 항상 쓰레기값을 갖기 때문에 반드시 초기화를 해줘야 한다.


📄정적변수

변수의 기억 영역을 프로그램이 끝날 때까지 계속 유지하려면 정적변수를 선언해주면 된다. static이라는 예약어를 사용하며 static으로 정적변수 선언이 이루어지면 정적인 기억 영역이 컴파일될 때 확보되어 변수에 할당된다. 정적인 기억 영역은 임시 기억 영역인 스택이 아닌 일반적인 기억 영역을 의미한다. 정적변수는 함수가 종료되거나 블록을 벗어나더라도 값이 계속 유지되어 프로그램 실행 중에 변수 속에 있는 값을 계속 보존할 수 있다. 따라서 모든 전역변수는 정적변수에 해당한다.

정적변수는 자동변수와 달리 컴파일할 때 한번만 기억공간이 할당되고 초기값이 부여된다. 특별한 지정이 없으면 정적변수는 0으로 초기화된다. 정적변수는 전역변수의 단점을 보완한다. 전역변수는 어디서나 접근이 가능한 반면 정적변수는 선언된 지역 내에서만 접근이 가능하다는 특징이 있고 다른 파일에서 참조할 수 없다는 특징이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

void static_test();

void main()
{
  int i = 0;

  while(i < 5)
  {
    static_test();

    ++i;
  }
}

void static_test()
{
  static int s;     // 정적변수 선언. 0으로 자동 초기화

  auto int a = 0;   // 자동변수 선언
  ++s;
  ++a;

  printf("static s = %d, auto a = %d \n", s, a);
}


📄외부변수

외부변수는 함수 외부에 선언되어 있다는 의미이다. 따라서 외부변수는 전역변수와 같다. 외부변수는 함수 밖에서 선언되어 프로그램이 종료될 때까지 값이 유지되고 초기값은 0을 갖는다. 전역변수, 정적변수와 외부변수가 다른 점은 다른 파일에서 외부변수로 선언된 변수 값을 참조할 수 있다는 것이다. 여러 개의 파일에서 변수를 공유하고자 할 때 유용하다. 외부변수를 사용하려면 extern으로 변수를 선언해주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// main.c

#include <stdio.h>
#pragma warning(disable:4996)

void extern_sample();

char s[10];                             // 전역변수 선언

void main()
{
  printf("문자열 입력: ");
  scanf_s("%s", s, 10);                 // 전역변수 s에 문자열 저장

  printf("문자열 %s는 전역변수 s에 저장 \n", s);
  extern_sample();
}



// sample.c

#include <stdio.h>

extern char s[];                        // 외부변수 선언

void extern_sample()
{
  printf("외부변수 s 값은 %s \n", s);   // 외부변수 출력
}


📄레지스터 변수

레지스터 변수는 CPU 내의 레지스터 자료를 저장할 때 사용된다. 레지스터로의 자료 입출력 속도가 기억장치 보다 빠르기 때문에 프로그램의 실행 속도를 높이기 위해 사용한다. 반복문에서의 카운터 변수로 많이 사용된다.

레지스터 변수는 자동변수와 같은 속성을 가지고 있고 보통 정수형 자료에 사용되며, 전역변수로는 선언될 수 없다. 하지만 CPU의 레지스터 개수는 한정되어 있어 되도록 자동변수를 사용하는 것이 좋다.


레지스터 변수 특징

  • 32bit 컴퓨터의 레지스터 크기는 4byte, 64bit 컴퓨터의 레지스터 크기는 8byte입니다. 이 크기를 넘어서는 자료형은 레지스터 변수로 사용할 수 없다.
  • 레지스터 변수는 기억공간에 저장되는 데이터가 아니므로, 포인터는 사용할 수 없다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

void main()
{
  register int a = 1;
  register long long b = 100;

  printf("a size = %d, b size = %d \n", sizeof(a), sizeof(b));
  
  b = 0;
  for(a = 0; a <= 10; ++a)
  {
    b += a;
  }
  --a;

  printf("a = %d, b = %lld", a, b);
}



Leave a comment