C 언어에서 변수와 데이터 타입은 앞선 내용에서 다루었습니다. 이번 글에서는 변수를 스코프(scope)와 가시성(visibility)을 기준으로 분류하는 스토리지 클래스(Storage Class)에 대해 자세히 알아보겠습니다.
핵심 개념 이해하기
스코프(Scope)
스코프는 일반적으로 변수의 생명 주기(lifetime)를 의미하는 용어입니다. 즉, 변수가 메모리에 얼마나 오래 유지되고 언제 소멸되는지를 나타냅니다.
가시성(Visibility)
가시성은 변수가 어느 위치에서 보이고, 어디에서 사용할 수 있는지를 뜻합니다. 예를 들어 지역 변수(local variable)는 다른 함수나 파일에서 접근할 수 없으므로, 선언된 블록 내부에서만 보입니다.
블록(Block)
블록은 두 개의 중괄호 { … } 사이에 있는 코드 줄들의 집합으로 정의됩니다.
{
//line1
//line2
//line3
}
위의 코드가 바로 하나의 블록입니다.
스토리지 클래스 비교표
| 스토리지 클래스 | 선언 위치 | 스코프 | 가시성 |
|---|---|---|---|
| auto | 전역(Globally) | - | - |
| auto | 지역(Locally) | 블록 | 블록 |
| register | 전역 | - | - |
| register | 지역 | 블록 | 블록 |
| static | 전역 | 프로그램 | 파일 |
| static | 지역 | 프로그램 | 블록 |
| extern | 전역 | 프로그램 | 프로그램 |
| extern | 지역 | 프로그램 | 블록 |
기본 문법
<스토리지 클래스> <데이터 타입> 변수_이름; 예시: static int my_var = 0;
참고: 스토리지 클래스를 지정하지 않고 단순히 <데이터 타입> 변수_이름; 형태로 선언하면 자동으로 'auto' 스토리지 클래스가 적용됩니다.
1. Auto (자동)
auto 스토리지 클래스는 모든 지역 변수에 적용되는 기본(default) 스토리지 클래스입니다.
{
int mount;
auto int month;
}
위 예제는 동일한 스토리지 클래스를 가진 두 개의 변수를 선언한 것입니다. 'auto'는 함수 내부, 즉 지역 변수에만 사용할 수 있습니다.
2. Register (레지스터)
register 스토리지 클래스는 RAM이 아닌 CPU 레지스터에 저장될 지역 변수를 정의할 때 사용합니다. 이는 변수의 최대 크기가 레지스터 크기(보통 한 워드, word)와 같다는 것을 의미하며, 메모리 위치를 갖지 않기 때문에 단항 연산자 '&'를 적용할 수 없습니다.
{
register int miles;
}
register는 카운터(counter)처럼 빠른 접근이 필요한 변수에만 사용해야 합니다. 또한 'register'로 선언했다고 해서 반드시 레지스터에 저장되는 것은 아니라는 점에 유의해야 합니다. 하드웨어 및 구현상의 제약 조건에 따라 레지스터에 저장될 수도 있고, 그렇지 않을 수도 있습니다.
3. Static (정적)
static 스토리지 클래스는 컴파일러에게 지역 변수를 스코프에 진입하고 벗어날 때마다 생성하고 소멸시키는 대신, 프로그램의 생명 주기 동안 계속 존재하도록 지시합니다. 따라서 지역 변수를 static으로 선언하면 함수 호출 사이에도 값을 유지할 수 있습니다.
static 한정자는 전역 변수에도 적용할 수 있습니다. 이 경우 해당 변수의 스코프가 선언된 파일 내부로 제한됩니다.
참고로 C++에서는 클래스 멤버 변수에 static을 사용하면, 해당 멤버의 단 하나의 복사본만 생성되어 클래스의 모든 객체가 이를 공유하게 됩니다.
Static 예제 코드
#include <stdio.h>
/* 함수 선언 */
void func(void);
static int count = 5; /* 전역 변수 */
main() {
while(count--) {
func();
}
return 0;
}
/* 함수 정의 */
void func( void ) {
static int i = 5; /* 지역 정적 변수 */
i++;
printf("i is %d and count is %d\n", i, count);
}
실행 결과
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
실행 결과에서 확인할 수 있듯이, static 변수인 i와 count는 함수 호출이 반복되더라도 초기화되지 않고 이전 값을 그대로 유지합니다.
4. Extern (외부)
extern 스토리지 클래스는 모든 프로그램 파일에서 볼 수 있는 전역 변수에 대한 참조(reference)를 제공할 때 사용합니다. 'extern'을 사용하면 변수를 초기화할 수 없으며, 이전에 정의된 저장 위치를 변수 이름이 가리키게 됩니다.
여러 개의 파일에서 하나의 전역 변수나 함수를 공유해야 할 때, 정의된 변수나 함수를 다른 파일에서 참조하기 위해 extern을 사용합니다. 쉽게 말해 extern은 다른 파일에 정의된 전역 변수나 함수를 선언(declare)하기 위해 사용됩니다.
따라서 extern 한정자는 두 개 이상의 파일이 동일한 전역 변수나 함수를 공유할 때 가장 많이 활용됩니다.
Extern 예제 코드 (main.c)
#include <stdio.h>
int count ;
extern void write_extern();
main() {
count = 5;
write_extern();
}
예제 코드 (support.c)
#include <stdio.h>
extern int count;
void write_extern(void) {
printf("count is %d\n", count);
}
실행 결과
count is 5
마무리 정리
auto: 지역 변수의 기본 스토리지 클래스
register: 빠른 접근이 필요한 변수에 사용 (실제 저장 여부는 컴파일러가 결정)
static: 지역 변수는 프로그램 종료 시까지 값 유지, 전역 변수는 파일 내부로 스코프 제한
extern: 다른 파일에 정의된 전역 변수·함수를 참조할 때 사용
네 가지 스토리지 클래스의 특징을 정확히 이해하면 변수의 생명 주기와 접근 범위를 효과적으로 제어하여, 더 안전하고 효율적인 C 프로그램을 작성할 수 있습니다.