안녕하세요 피터입니다.

오늘은 C언어에서 사용되는 Storage Class에 대해 설명드리겠습니다.

기억 영역 분류 (Storage Class)


Storage Class는 C언어에서 기억 영역을 분류하기 위해서 사용되는 용어입니다. 이 용어는 한글로 번역하기가 애매한 부분이 있는데 일반적으로 기억 영역 분류 또는 기억류 라고 번역되어 쓰이고 있습니다. 

이 stroage class는 class 라는 단어가 들어있습니다만, 여기서의 쓰임새는 C++ 의 'class' 키워드와는 전혀 관련이 없습니다. 단지 어떤 것의 종류를 의미하는 사전적인 의미로 class가 쓰인 것입니다. 

C언어의 storage class에는 auto, register, static, extern 4가지 종류가 있습니다.

각각의 class는 상호 배타적이라서 두 가지 이상의 키워드를 함께 사용할 수 없습니다. 


1. auto

auto는 지역변수를 선언할 때 아무것도 지정하지 않았을 때 기본값으로 지정되는 storage class 입니다. 

{
   int count;
   auto int count;
}

auto는 함수 내에서만 사용이 가능하며(지역 변수) 위 두 구문은 의미가 같습니다.

(사실 실제로 auto 키워드를 사용할 일은 거의 없습니다)


2. register

register는 변수가 메모리 대신 레지스터에 저장되면 좋겠다는 희망사항을 컴파일러에게 알려주는 storage class 입니다. 

레지스터에 저장된 변수에는 메모리에 저장된 변수보다 훨씬 더 빠르게 접근할 수 있으므로 성능 향상을 꾀할 수 있습니다. 

레지스터에 저장되려면 변수의 크기가 레지스터 사이즈보다 같거나 작아야 합니다. 일반적으로 1 word를 저장할 수 있습니다. 그리고 레지스터는 메모리처럼 주소값을 갖을 수 없기 때문에 변수의 주소값을 구하는 & 연산자는 사용할 수 없습니다.

{
   register int  miles;
}

register 지시자를 사용했다고 해서 반드시 레지스터에 저장되는 것은 아닙니다. 그저 '레지스터에 저장했으면 좋겠다' 정도인 것입니다. 

최근 나온 컴파일러들은 최적화를 수행하면서 레지스터를 잘 활용하기 때문에 register 지시자를 무시할 확율이 높습니다. 

(결론적으로는 실제로 사용할 일이 거의 없습니다.)


3. static

이전 강좌에서 변수의 Scope에 대해서 설명드렸던 것 기억하시나요?

지역 변수(Local variable)의 경우에는 함수 내에서만 유효하다고 말씀드렸습니다. 함수를 빠져나가는 순간. 즉 '}' 를 만나는 순간 지역 변수는 스택에서 제거됩니다. 

같은 함수를 다시 호출했을 때 예전에 사용하던 지역 변수는 이미 삭제되어 값을 유지하지 못합니다. 같은 이름의 새로운 지역 변수가 스택에 생성되었기 때문이죠. 

그런데 static 지시자를 사용해서 생성한 지역 변수는 함수를 빠져나가도 값을 유지할 수 있습니다. 변수의 생명 주기(Life cycle)이 달라지게 되는거죠.  그렇다고 해서 다른 함수에서 접근이 가능해지는 것은 아니니 혼동하지 말아주세요.

static은 전역 변수에도 사용할 수 있습니다. 전역 변수를 static으로 지정하면 해당 변수의 Scope을 선언된 파일 내로 제한합니다. 

아래 예제 코드를 봐주세요. 

#include <stdio.h>
 
/* function declaration */
void func(void);
 
static int count = 5; /* global variable */
 
main() {

   while(count--) {
      func();
   }
	
   return 0;
}

/* function definition */
void func( void ) {

   static int i = 5; /* local static variable */
   i++;

   printf("i is %d and count is %d\n", i, count);
}

count라는 전역 변수에 static을 사용해서 Scope를 파일 내로 제한했습니다. 

func() 함수 내에서 선언된 지역 변수 i 의 경우 함수 호출이 끝나더라도 값을 유지해서 다음 호출 시 늘어나는 것을 아래 실행 결과에서 볼 수 있습니다.  

static int i = 5; 이 초기화 구문은 변수가 처음 생성될 때만 유효하기 때문에 첫 번째 함수 호출 시에만 실행됩니다. 그 이후 호출 시에는 무시되죠. 

함수가 호출될 때마다 생성 - 파괴가 반복되는 일반적인 지역변수와는 전혀 다르게 동작하죠. static을 빼고 테스트 해보시기 바랍니다. 

실행 결과

i is 6 and count is 4

i is 7 and count is 3

i is 8 and count is 2

i is 9 and count is 1

i is 10 and count is 0


4. extern

extern은 프로그램을 구성하는 파일들이 여러 개일 때 다른 파일에서 정의된 전역 변수나 함수를 접근할 수 있게 참조(reference)를 제공해주는 지시자입니다. 

다만 extern으로 선언된 외부 전역 변수는 초기화할 수 없습니다. 

아래 예제 코드를 봐주세요.

main.c

#include 
 
int count ;
extern void write_extern();
 
main() {

   count = 5;
   write_extern();
}

support.c

#include 
 
extern int count;
 
void write_extern(void) {
   printf("count is %d\n", count);
}

main.c 파일에서 선언된 전역 변수 count를 support.c 에서 extern으로 선언하여 printf하고 있습니다. 

또한 support.c에서 선언된 write_extern 함수를 main.c에서 extern으로 선언하여 호출하고 있습니다. 

이런식으로 여러 개의 파일에서 전역 변수를 공유하고 싶을 때는 extern을 사용하여 같은 이름의 변수 또는 함수를 선언하면 됩니다. 

컴파일 및 실행 결과

$gcc main.c support.c
$./a.out

count is 5


여러분의 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.

-Peter의 우아한 프로그래밍

블로그 이미지

Awesome PeterAhn

IT 정보 공유, 프로그래밍 지식 공유, 훌륭한 개발자가 되어보자