'먼저 헤더파일에는 함수 선언하여라' 라고 권하고 싶다.
이유는 혼동이 될 수 있는 함수와 변수의 차이 때문이다. 함수는 기본적으로 extern이다.
void func(); 와 int a; 는 근본적으로 다른 선언이다.(C는 조건부,C++에서는 무조건 다름)
void func()는 func()가 어딘가에 있어! 라고 말해주는 표시등이고, int a라 선언하면 데이터 영역에 a가 쓰여진다.
이런 차이로 프로그램에서 전역으로 선언된 a가 있는 헤더파일이 불려지는 횟수 만큼 초기화가 일어난다. 결국 스택이 아닌 정적영역에서 이름이 충돌하므로 에러가 생긴다.
헤더파일에 변수를 extern으로 선언하면?
a.h에 extern int a; 와 b.h에 extern int b;가 선언되어있고, 각 cpp 파일에 변수가 정의되어 있다.
a.h 와 b.h를 main.cpp 에서 include 하면 이 경우는 초기화가 되는 것이 아니므로 제대로 수행이 된다.
경우에 따라 다르겠지만, 선택은 사용자의 몫..
그러면 static에 대해서 알아보자. 흔히 잘못 알고 있는 프로그래밍 상식 중 하나가 이 static 함수나 변수의 헤더파일에서의 사용이라고 생각한다.
만약a,b각 모듈을 만든 회사가 동일한 함수명을 사용하여 충돌이 발생된다면?
"이 경우는 static으로 선언하면 된다." 라고 많은 책이나 문서에 설명되어 있지만. 정확히 말하면 cpp파일에 static으로 정의해야 한다. 필자는 경험적으로 배운 사실이므로 이를 증명할 수 있는 건 필자의 경험 뿐이다.(믿거나 말거나).
아무튼 이 static의 다형적인 특성 때문에 안 그래도 헷갈리는 static!, 간단한 예로 왜 static을 헤더에 사용하지 말아야 하는지 설명하겠다.
2015/06/18 - [프로그래밍/C언어] - 지역변수와 전역변수와 정적변수[static, extern, auto, register]
2015/06/18 - [프로그래밍/C언어] - 전역 변수를 지역변수로 만들면? (static과 extern에 대한 이야기)
지난번 설명한 번역단위를 떠올리자. a모듈과 b모듈에서 동일한 명의 함수가 존재한다고 하자. 사용자는 두 개의 모듈이 모두 필요하고, 동일한 명의 함수 중 하나의 함수만 사용하길 원한다. b모듈의 test()함수만 사용하고 a모듈의 test()함수는 사용하지 않을 예정이다.
위 문제를 해결하기 위해서 a.h의 선언부분에 가서 test()함수를 static으로 만들면?
한번 따져보자 main.cpp에 다음과 같은 두 개의 문장이 추가될 것이다.
static void test();
void test();
위 두 문장을 가볍게 넘기면 안 된다. 만약 하나의 모듈을 만들 때 위와 같이 선언한다면? 누가 봐도 에러가 생긴다는 것을 알 수 있다.
이에 대해서 따지다 보면 대단히 머리가 아파옴을 알 수 있다. 굳이 따지자면
static void test(); // 이 선언은 a의 모듈의 함수를 위한 것이지만, main에서는 그냥 문자 그대로를 해석하기 때문에, 자신의 모듈에서 static으로 선언된 것으로 인식한다. 실제로 main에서 test()함수에 대한 정의를 하게 되면 제대로 수행된다. void test();의 경우는 내부적으로 어떻게 동작하는지는 잘 모르지만 에러를 발생시키지 않는다. 아무튼 위 방식대로 라면 모듈의 test()함수는 사용하지 못하여 의미가 없게 된다.
여기서 include 순서를 바꿔보면
void test();
static void test();
이 경우는 extern 으로 선언한 함수를 static으로 다시 선언하면 안 된다고 에러가 뜬다. 심지어 include 순서까지 영향을 준다. 그래서 이에 대해서 논하는 것은 그렇게 가치있는 일이 아니다. 결론은 헤더파일에 static을 사용하지 않으면 해결될 문제고, 이런 지침을 따르기만 하면 된다.
.c 또는 .cpp 파일에 static함수를 정의하면 된다.
제대로 된 설계를 하기 위해서는 헤더파일에는 함수의 선언만, 각 모듈간에는 함수명이 충돌하지 않도록 해야 한다.