사실 이 두 지정자는 그렇게 복잡한 녀석들은 아니지만 메모리의 모습과 컴파일 과정과 맞물린 성질을 가지고 있기 때문에 확실히 개념을 잡지 않으면 그냥 저냥 이해하고 넘어가게 된다.
extern
우선 extern이란 지정자는 간단한 예제 프로그램에서는 거의 등장하지 않는다. 왜냐면 extern으로 선언된 변수가 있다면 이 변수는 전역 변수로 어디엔가 선언되어 있다는 의미를 가지고 있는데 일반적인 예제 프로그램들의 전역변수는 코드의 앞 부분에 미리 선언되므로 굳이 extern 지정자를 사용할 필요가 없기 때문이다. 코드는 순서대로 메모리에 올라가게 되고 이 순서만 맞춰서 전역 변수가 메모리에 우선 올라가 있다면 어디서든 접근이 가능하기 때문이다.
반대로 이 순서라는 것이 발목을 잡을 수가 있다. 예를 들어 전역 변수지만 코드 순서에서 사용처보다 뒤쪽에 정의되어 있다면 사용처에서 해당 변수를 알지 못한다.(아직 메모리에 올라오지 않았으므로) 이런 경우 해당 변수를 미리 extern으로 선언해서 알려줄 필요가 있다. 물론 extern은 사용처 보다 앞쪽에 선언되어야 된다.
이렇게 코드를 작성할 때 순서라는 것은 중요하다. 일반적으로 하나의 모듈(cpp파일)에 모든 코드가 작성된 경우는 굳이 extern을 사용할 필요가 없다. 변수의 선언 순서를 코드의 앞쪽에 위치시키면 해결 되기 때문이다. 그러나 모듈이 여럿인 경우는 외부에서 정의된 변수의 존재를 컴파일 과정에서 절대 알 수가 없다.
우리가 코드를 컴파일 하면 컴파일이 이루어 진 후 링크과정이 이루어 진다. 여러 개의 cpp파일이 있을 때 cpp파일은 하나의 번역단위가 된다. 물론 cpp파일이 포함하는 헤더파일이 있다면 cpp파일과 포함된 헤더파일이 하나의 번역 단위가 된다. 어쨌든 번역단위는 cpp파일을 기준으로 이루어지고 이런 번역단위가 컴파일 되어 하나의 목적파일이 된다.
여기서 생각해 봐야할 문제는 다양한 모듈을 포함하는 하나의 프로그램이 어떻게 모듈간에 함수와 변수를 공유할 수 있느냐는 것이다. 바로 extern지정자로 외부 모듈 어디엔가 함수나 변수가 선언되어 있다고 정보를 알려줌으로써 컴파일 시에 식별자를 찾지 못한다는 에러를 일으키지 않고 컴파일 과정을 무사히 통과할 수 있는 것이다.
비유하자면 extern은 이런 느낌이다. A라는 사람은 지금 당장은 아니지만 연필이 필요하다. 현재 A라는 사람이 가지고 있는 서랍은 4개가 있다. 그리고 누군가 귀뜸해 준다.
4개의 서랍 중 연필이 어디엔가 있어!
여기서 누군가가 귀뜸해주는 행위가 extern이다. 4개의 서랍은 다른 모듈(cpp파일)을 말한다.
코드가 컴파일 되는 경우라면 이 경우 연필이 있다고 확신하고 컴파일이 된다. 실제로는 4개의 서랍 어디에도 연필이 없을 수도 있다. (이런 경우에는 컴파일은 되더라도 링크시에 에러가 난다.)
이렇게 extern은 컴파일러에 믿음을 주는 행위다. 그 믿음이 진실인지 아닌지는 링크과정에서 판별난다. 이것은 순전히 모듈화 프로그램을 위한 것이다.
한가지 예를 더 들면 여러 공장에서 부품을 생산하는데 이 부품들은 조립을 하는 최종 공장으로 모두 들어온다. 이 때 각 공장에서 만드는 부품들은 서로 밀접한 관계가 있다. A라는 공장의 부품이 사용되기 위해서 특정 볼트가 필요하다고 한다면 A공장의 관리자는 그 볼트를 직접 생산하던가 아니면 외부 공장 어딘가에서 해당 볼트가 생산됨을 확신하고 있어야 한다. 만약 외부 공장에서 해당 볼트를 생산한다면 A공장 생산자들에게 "볼트는 있으니까 만들필요 없어" 라고 알려줄 것이다. 이것이 바로 extern이다.
따라서 A공장 생산라인은 문제없이 컴파일 되고 만약 최종 공장에서 볼트가 없다면 최종 공장(링크과정)에서 에러가 날 것이다.
마지막으로 우리는 헤더파일을 만드는데 바로 이 헤더파일의 목적이 바로 extern을 위한 것이다. 외부에 공개하기 위해 선언해 놓는 함수들을 보통 헤더파일에 선언해서 공개한다. 단순히 이 헤더파일을 포함하는 것만으로도 우리는 외부 모듈에 선언된 함수에 대한 extern선언을 하는 것과 마찬가지 인 것이다.
그런데 왜 함수는 선언 앞에 왜 extern 지정자가 안 붙어요? 라고 생각할 것이다.
함수는 변수와 달리 선언 시에 자동으로 extern이 붙는다.
결국 붙여도 안붙여도 같은 의미다.
static
그럼 staic은 무엇인가? 일반적으로 정적 변수, 메모리 데이터 영역에 위치하여 프로그램 시작 시에 생성되어 프로그램 종료시에 소멸되는 변수라는 특징을 지닌다는 것은 대부분 알고 있을 것이다.
일반적인 특징 외에 컴파일 과정과 맞물려 생각해 볼 필요도 있다.
모듈 내부에서 static으로 선언된 변수나 함수의 경우는 해당 모듈에서만 사용이 가능하다. 이 말은 컴파일 시에 결정되는 요소라는 뜻이다. 즉 번역단위(cpp파일+포함된 헤더파일) 내에서만 사용가능한 요소라는 뜻이다. 앞서 extern으로 선언된 변수나 함수는 컴파일 과정에서는 있다는 사실만 알려주고 링크과정에서 최종 결정이 되었다. 이렇게 컴파일 링크 과정과 맞물려 생각하면 좀 더 수월하게 extern과 static의 성질을 이해할 수 있으리라 생각든다.