C auto, static, extern 키워드 의미

C에서 변수는 값이 저장되는 메모리 영역이나 변수의 유효범위에 따라 구분되는데 auto, static, extern 이 세가지 키워드(keyword)를 이용하여 구분을 할 수 있다.

변수의 유효범위는 크게 지역변수(local variable)와 전역변수(global variable)로 나뉘며, 실제 프로그램 실행시에 변수가 저장되는 메모리상의 위치에따라 높은 주소값부터 거꾸로 사용하여 내려오는 스택(stack)과, 낮은 주소값부터 올라가면서 사용하는 정적데이터영역(.data, .bss)과 힙(heap)으로 구분된다1. 최적화 관점에서 살펴보면, 스택의 경우 해당 범위(scope)에서 자주 액세스 되며 범위가 끝나면 없어지는 임시변수들이 저장되는데, 스택포인터를 순차적으로 이동해가면서 할당되기 때문에 할당속도가 빠르며, 해당 변수들이 자주사용되어서 CPU 캐시의 힛트율이 높은 경우 접근 속도도 더 빨라질 가능성이 있다. 하지만 범위가 끝나면 없어지기때문에 계속적으로 값을 유지하는 것이 불가능하다. 이러한 문제를 해결하기위해서는 정적인 변수들은 정적 데이터 영역에 저장하여 계속 유지되며, 동적인 변수들은 힙에 변수를 할당하고 저장해야한다. 힙은 비순차적으로 메모리 할당/해제가 계속 일어나는 동적인 특성을 갖고있다. 때문에 스택처럼 메모리 할당을 순차적으로 하기가 힘들어서 정적인 방식에 비해 할당 속도가 느린 특성을 갖는다.

이제 각각의 키워드에 따라 해당 변수의 유효범위와 저장되는 영역이 어떻게 결정되는지를 케이스별로 살펴보도록 하자.

  1. auto (자동범위변수)
    • 일반적인 지역 변수 형태로 블럭 안에서만 유효하며 블럭의 실행이 끝나면 소멸
    • 스택에 메모리 할당
    • 일반적으로 C에서 auto 키워드는 생략되어있음. 즉 아무 표시하지 않은 변수는 auto와 같은 의미.
    • C++에서 auto 키워드를 사용할 경우 “자동 타입 추론”이라는 완전히 다른 의미를 가지게되므로 주의할것.
  2. static (정적변수)
    • 블럭 안에서만 유효한 값을 가지지만 자동변수와 같이 없어지지 않고 블럭으로 다시
      돌아왔을 때 이전 값을 다시 이용 가능(스택이 아닌 정적데이터 영역에 저장됨)
    • 초기화를 생략하면 0으로 자동 초기화
    • 정적 데이터영역에 할당
    • static사용되는 위치에 따라 의미가 달라지니 주의해서 사용할것.
      • 내부정적변수 : 함수 내부의 변수에 static이 사용된경우, 해당 변수는 함수 내부에서만 사용이 가능. 하지만, 프로그램이 실행되는 동안 계속 값이 유지됨
      • 외부정적변수 : 함수 외부의 전역범위의 변수에 static이 사용된경우, 해당 파일 내부에서는 전역변수처럼 사용되지만, 아닌 다른 소스파일에서는 참조할 수 없음
        (예: 보통 하나의 example.c 파일 내부에서만 사용하기위한 전역변수로 사용됨. 다른 파일이 example.h를 include하더라도 해당 static으로 선언된 전역변수는 보이지 않아 접근 불가)

    static_example.h

    static_example.c

    myfunction.c

  3. extern (외부변수)
    • 함수 밖의 전역 범위에 선언되며, 프로그램 전체에서 유효하고 다른 파일에서도 참조 가능
    • 초기화를 생략하면 0으로 자동 초기화
    • 정적 데이터영역에 할당
    • extern 변수는 편리하지만 남발하면 프로그램을 복잡하게 하고 나중에 유지보수가
      힘들기 때문에 사용을 최소화 하는 것이 바람직함

    • 외부변수 정의하는 방법은 아래 extern_example 예제를 참조하고 실제 이를 다른파일에서 사용하는 예시는 myfunction.c 를 보면된다.

    extern_example.h

    extern_example.c

    myfunction.c

  • Pingback: KVO 컨텍스트 표현을 위한 자기참조 포인터 | Knowledge Logger

  • Taehee Jeong

    static, extern 변수 등은 heap 이 아니라 .data 나 .bss 영역 등에 저장됩니다. (bss 영역은 확실치는 않네요)
    heap에는 run-time에서 동적 할당된 데이터들이 주로 들어갑니다.
    처음에 동적 할당을 할 때, 그리고 할당을 해제할 때는 스택과 속도 차이가 나지만, 스택 안에 있는 배열과 힙 안에 있는 배열에 대해 for 문을 돌리는 경우를 생각해 보면 속도 차이는 없습니다. ^^

    • http://www.letmecompile.com/ YoungJae Kwon

      낮은 주소값영역부터 global/static변수들이 저장되고, heap 영역이 사용되는것은 알고있었지만 global/static변수들이 저장되는 공간이 .text .data .bss 등의 이름을 갖고있는것은 몰랐었네요. 얕은 지식갖고 정리해서 쓰다보니 틀린점이 많았네요. 코멘트 감사합니다.

  • KukiYome

    잘못된 내용이 너무 많습니다.

    1. auto는 자동변수가 아닙니다. 컴파일 타임에서 대입되는 값에 맞춰 형이 결정됩니다. 컴파일러가 형을 결정하도록 할 뿐, 결국 특정한 자료형을 가지는 일반 변수입니다. 너무나도 긴 자료형을 일일이 타자치는것을 방지하기 위해 생긴 키워드입니다.
    std::vector vec; 라고 선언되어있을 경우
    ex) std::vector::iterator* iter = vec.begin();
    -> auto iter = vec.begin();

    C/C++에서는 구조적으로 자동변수를 구현할 수 없습니다.

    2. 변수선언시 변수형 지정을 생략하면 이는 이미 변수선언이 아닙니다. auto키워드 역시 생략할 수 없습니다.

    3. 전역변수/정적변수는 힙에 할당되지 않습니다.정적 데이터 영역이라는 공간에 별도로 할당되며 엔트리포인트(메인함수) 진입전에 초기화됩니다.

    4. 스택, 힙, 전역 데이터 영역에 접근하는데 있어 성능차이는 존재하지 않습니다.

    5. extern 키워드는 ‘다른파일에서도 참조가능한 전역변수’가 아닌, ‘다른 파일에 선언된 전역변수를 참조하기 위한’ 키워드입니다.

    • http://www.letmecompile.com/ YoungJae Kwon

      안녕하세요,

      1, 2번: C에서 쓰이는 auto 키워드와 C++에서 쓰이는 auto 키워드가 의미가 다르네요. 이부분 제가 정확히 알지 못하고 C/C++이라고 두가지를 포함하여 명시한점 수정하도록 하겠습니다. 제가의도했던 내용은 C에서 쓰이는 local variable 선언들의 경우 implicit하게 이미 auto 키워드를 사용하는것과 동일하다는 것만 말하려고했는데 잘못되었던것 같네요 C++을 삭제하도록 하겠습니다.

      3, 4번: 제가 정확히 알고있지 못했네요 지적 감사합니다.

      5. ‘다른파일에서도 참조가능한 전역변수’ 는 해당 파일의 전역변수 선언부에 코멘트로 제가 달아놓은 내용입니다. extern 키워드의 의미가 그렇다는게 아니고 해당 파일에 선언된 전역변수를 다른파일에서도 참조가능하다고 적어놓은건데 말이 좀 애매했나요? 오해하신듯 하네요.

      시간내서 지적해주셔서 감사합니다. 제대로 알고있지 못했던 부분에대해 좀더 공부할기회가 된것 같습니다. 잘못된 부분에은 수정해서 다시 올리도록 하겠습니다.

  • Hyogi Jung

    블로그에 내용도 많고, 깔끔하게 정리되어 있네 ㅋㅋ
    새로운 것들도 많고, 이건 설치형 wordpress 라 기능이 더 많은거야?
    밑에 댓글들 많이 까칠하네 ㅋㅋ 그래서 지금은 잘 정리된 듯 해 ㅎㅎ

    extern (외부변수) 설명에서 (계속 값을 유지해야 하기때문에 힙에 저장해야함) 이건 깜빡하고 수정 못한 거 같고,
    static, extern 설명 때 ‘계속 값을 유지해야 하기 때문에 스택이 아닌 정적데이터 영역에 저장됨’이라고 설명했는데 이 말이 조금 애매하지 않나?

    static, extern, global 변수를 data 영역에 저장하는 이유가,
    프로그램 실행 중에 계속 값을 유지하기 위해서도 있지만 다른 이유들도 있으니까
    저 이유면 정적 데이터 영역이 아닌 heap 도 가능하잖아 ㅎㅎ

    자주 놀러 올께 ㅋㅋㅋ 참고 많이 해야지 ㅋㅋ

    • http://www.letmecompile.com/ YoungJae Kwon

      음 뭔가 요약해서 쓰다보니 자꾸 말이 애매해지는 게 없잖아 있는듯ㅎㅎ 글쓰는게 쉽지 않네.

      static, extern, global 변수를 data 영역에 저장하는 이유가,
      프로그램 실행 중에 계속 값을 유지하기 위해서도 있지만 다른 이유가 따로있는건가? 컴파일타임에 이미 바이너라 안에 공간을 확보한 상태라 굳이 heap에 넣을필요가 없는거로 생각했는데.. 따로 이유가있는지 궁금하네 ㅋ 컴파일러 공부한지가 오래되서 가물가물.. 조언좀 ㅋ

      • Hyogi Jung

        음, 뭔가 명확하게 하고 싶었는데 나도 잘 몰라서 ㅎㅎ

        나는 ‘계속 값을 유지해야 하기 때문에 스택이 아닌 정적데이터 영역에 저장됨’ 이 말이 이상했어, 순서가 바뀐 느낌이랄까?
        틀린 말은 아니지만 그 이유라면 데이터 영역이 아닌 heap을 사용 할 수도 있는거잖아?

        다른 이유들은 (물론 아는 내용이겠지만) stack 영역은 실제 그 부분이 호출 되었을 때 (run time), heap 영역도 메모리를 할당하였을 때 (run time) 지만, data 영역의 변수들은 compile time에 얼마나 필요한지 결정하고, 메모리를 할당하기 때문에 이로인해 프로그램이 종료될 때까지 유지되고, 전역으로 접근 가능하고

        이 순서가 맞을 듯 싶은데 ㅎㅎ 나도 잘 몰라 이상한 부분있으면 집어줘 ㅎㅎ

        • http://www.letmecompile.com/ YoungJae Kwon

          사실은 맞는데 인과관계가 이상하게 표현되서 그런거였군 땡스ㅋ