6-4-마.C프로그램의 구조

2장 마지막에서 C프로그램은 대체로 다음과 같은 구조를 가진다고 했다. 물론 필요에 따라 순서를 조금씩 바꿀 수 있겠지만 여러 사람들이 오랫동안 C로 프로그래밍을 해 본 결과 이 구조가 가장 이상적이라는 것을 알게 되었으며 그래서 대부분의 C 소스는 이런 구조로 만들어진다. 처음 배울 때는 남들 하는대로 일단 따라하는 것이 좋다.

 

#include <...>

#define ...

함수의 원형

전역변수

 

void main()

{

     코드

}

함수

함수

함수

 

제일 먼저 헤더 파일을 포함하는 #include 문이 오고 다음으로 매크로를 정의하는 #define이 온다. 그리고 이 프로그램이 사용하는 함수의 원형과 전역변수를 선언하고 main 함수가 가장 먼저 오며 main 함수 다음에 사용자 정의 함수를 작성한다. 이 방식대로 코드를 작성하면 제일 말썽이 없고 코드를 유지 보수하기에 편리하다.

이 구조에서 두 개의 전처리문인 #include와 #define의 순서에 대해 조금 더 생각해 보자. 매크로 정의와 헤더 파일을 포함하는 것은 별개의 동작이기 때문에 순서가 그리 중요하지 않을 것 같다. 하지만 #define이 #include보다 먼저 오는 것은 바람직하지 않은데 왜 그런지 예제를 만들어 보자. 다음 예제는 MessageBox라는 API 함수를 사용하여 메시지 박스를 보여준다.

 

: defineorder

#include <Turboc.h>

#define lpText "매크로의 주의 사항 테스트를 위한 메시지 박스입니다."

 

void main()

{

     MessageBox(NULL,lpText,"제목",MB_OK);

}

 

보여줄 메시지 내용은 lpText라는 이름의 매크로로 정의했으며 MessageBox 함수의 두 번째 인수에 lpText 매크로를 사용했다. 이 구조대로 소스를 작성하면 아무 문제없이 컴파일도 잘 되고 실행도 잘 된다. 그런데 전처리문의 순서를 바꾸어서 #define을 먼저 쓰고 그 아래에 #include를 쓰면 winuser.h 헤더 파일에서 괄호가 빠졌다는 둥, 세미콜론이 없다는 둥 하는 회괴망칙한 이상한 에러가 난다.

 

winuser.h(6138) : error C2143: syntax error : missing ')' before 'string'

winuser.h(6138) : error C2143: syntax error : missing ';' before 'string'

winuser.h(6138) : fatal error C1004: unexpected end of file found

 

왜 이런 에러가 나는지 winuser.h 파일을 열어 보면 알 수 있다. 이 헤더 파일에는 MessageBox 함수의 원형이 다음과 같이 선언되어 있다.

 

int MessageBox(HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType);

 

윈도우즈의 표준 헤더 파일은 형식 인수의 이름을 표시하는 완전한 원형을 제공하는데 이 원형에서 두 번째 인수의 이름 lpText가 매크로 lpText와 이름이 같다. 그래서 함수 원형의 lpText까지도 매크로로 치환되어 버리며 원형에 이상한 문자열이 들어가 있으므로 컴파일러가 함수의 형태를 제대로 파악하지 못하는 것이다.

이 문제를 해결하려면 프로그램에서 정의하는 lpText 매크로의 이름을 다른 것으로 바꾸어 표준 헤더 파일에 있는 형식 인수 이름과 충돌하지 않도록 하면 된다. 그러나 그보다 더 완전하고 확실한 해결책은 #include를 #define보다 앞쪽에 두는 것이다. 이렇게 되면 lpText를 정의하기 전에 헤더 파일을 읽으므로 명칭의 충돌이 사라진다.

아주 특수한 매크로의 경우는 헤더 파일을 포함하기 전에 먼저 정의해야 하는 것들도 있는데 주로 컴파일 옵션이나 환경 정의를 하는 매크로들이다. 이런 특수한 매크로들만 제외하고 프로그램이 정의하는 매크로들은 헤더 파일을 먼저 포함한 후 정의하는 것이 좋다. 헤더 파일을 포함하는 #include 문 자체에도 순서가 있는데 가급적이면 표준 헤더 파일을 먼저 포함한 후 사용자 정의 헤더 파일을 포함시켜야 한다.