|

C 언어 static 키워드는 왜 헷갈릴까: 지역 변수, 전역 함수, 파일 범위에서 다른 의미

C 언어 static 키워드는 왜 헷갈릴까: 지역 변수, 전역 함수, 파일 범위에서 다른 의미
C의 static은 위치에 따라 저장 기간과 파일 밖 공개 범위를 다르게 바꿉니다.

C 언어 static은 같은 키워드인데도 지역 변수 앞에 붙을 때와 전역 함수 앞에 붙을 때 느낌이 다릅니다. 그래서 단순히 ‘정적’이라고 외우면 실제 코드에서 금방 헷갈립니다.

핵심은 저장 기간과 연결 범위를 따로 보는 것입니다. 이 글은 C 언어 공식 문법 자료를 기준으로 block scope static, file scope static, internal linkage를 나눠 설명합니다.

C 언어 static 의미 구분 요약 카드
static을 외울 때는 값이 얼마나 오래 사는지와 어디에서 보이는지를 나눠 봐야 합니다.

static을 먼저 두 갈래로 나누자

C에서 static은 문맥에 따라 두 가지 질문에 답합니다. 첫째, 이 변수의 값은 얼마나 오래 살아 있는가. 둘째, 이 이름은 다른 .c 파일에서도 보이는가.

  • 함수 안 지역 변수 앞의 static: 저장 기간을 프로그램 전체로 늘린다
  • 파일 범위 변수나 함수 앞의 static: 이름을 현재 translation unit 안으로 숨긴다

이 두 효과를 한 문장으로 섞어 외우면 헷갈립니다. 위치를 먼저 보고 저장 기간과 linkage를 따로 읽어야 합니다.


지역 변수 static은 호출 사이의 값을 기억한다

함수 안에서 선언한 일반 지역 변수는 함수 호출이 끝나면 사라집니다. 하지만 static 지역 변수는 block scope를 가지면서도 static storage duration을 가져서 다음 호출 때도 이전 값을 유지합니다.

int next_id(void) {
    static int id = 0;
    id += 1;
    return id;
}

이 코드는 호출할 때마다 1, 2, 3처럼 증가합니다. 다만 값이 숨겨진 상태로 남기 때문에 테스트와 동시성 관점에서는 신중하게 써야 합니다.


파일 범위 static은 이름을 숨긴다

.c 파일 최상위에 있는 변수나 함수에 static을 붙이면 그 이름은 보통 현재 translation unit 내부에서만 연결됩니다. 다른 .c 파일에서 같은 이름을 쓰더라도 서로 충돌하지 않게 만들 수 있습니다.

// user_repository.c
static int cache_size = 0;

static void reset_cache(void) {
    cache_size = 0;
}

이 방식은 내부 helper 함수와 내부 상태를 숨길 때 유용합니다. 공개 API는 헤더에 선언하고, 내부 구현은 .c 파일 안에 가두는 식입니다.


헤더 파일에 static 정의를 둘 때의 주의점

헤더는 include된 위치에 내용이 펼쳐집니다. 헤더에 static 변수나 함수를 정의하면 그 헤더를 include한 각 .c 파일마다 별도 이름과 저장 공간이 생길 수 있습니다.

작은 inline helper처럼 의도한 경우도 있지만, 공유 상태라고 착각하고 헤더에 static 변수를 넣으면 파일마다 값이 따로 움직이는 버그가 생길 수 있습니다.


실무 체크리스트

  1. static이 함수 안에 있는지 파일 최상위에 있는지 먼저 본다
  2. 지역 static은 상태가 숨어도 괜찮은지 검토한다
  3. 파일 내부 helper 함수는 static으로 숨기는 편이 좋다
  4. 공유해야 하는 선언은 헤더에 두되 정의는 .c에 둔다
  5. 헤더의 static 정의가 파일별 복사본을 의도한 것인지 확인한다

정리

static를 이해할 때는 문법이나 기능 이름보다 문제가 생기는 경계를 먼저 보는 편이 좋습니다. 오늘 글의 기준은 ‘언제 다시 실행되고, 어디까지 공개되고, 어떤 권한이 남는가’처럼 실수 지점을 분리하는 것입니다.

함께 보면 좋은 내부 글은 C 언어 헤더 파일은 왜 나눌까, C 언어 struct는 언제 쓰는가, C 언어 배열과 포인터는 같은 걸까입니다. 외부 기준은 cppreference – Storage-class specifiers, cppreference – Scope, cppreference – External and tentative definitions를 확인했습니다.

함께보면 좋은 글