버전 매크로

@codemaru · July 06, 2010 · 6 min read

비주얼 C++을 이용해 프로젝트를 처음 만들게 되면 stdafx.h에는 다음과 같이 알 수 없는 전처리기 구문이 생성된다. 기초 서적에서 이와같은 부분을 별도로 설명하지 않기에 대부분의 사람들은 그저 그냥 생성된 구문이겠거니 하고 넘어가게 된다. 하지만 이 부분에 대해서 정확하게 이해하지 못하고 넘어가는 경우, 최신 API를 사용하려고 할 때에 나타나는 컴파일 에러에 당황할 수 있다. 그렇다면, 이번 기회를 통해 간단하게 복습하는 기분으로 다음의 전처리기 구문에 대해 살펴보도록 하자.

#ifndef WINVER
#define WINVER 0x0400
#endif

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

#ifndef _WIN32_WINDOWS
#define _WIN32_WINDOWS 0x0410
#endif

#ifndef _WIN32_IE
#define _WIN32_IE 0x0400
#endif

#define은 개발자라면 많이 접하고, 익히 알고 있을 것이다. 상수를 선언하는 것이다. 위에서 제일 첫 번째 나온 WINVER부분을 보면 WINVER를 0x0400으로 정의하고 있다는 것을 알 수 있다. 따라서 앞으로 소스의 모든 WINVER는 0x0400으로 치환된다.

#define 위에 있는 #ifndef, #endif는 조건부 컴파일을 하는 전처리기다. #ifndef는 뒤에 나오는 상수가 선언되지 않은 경우, 다음 부분을 컴파일할 것이라는 것을 말한다. 첫 번째 블록은 결과적으로 WINVER가 선언되지 않은 경우에 WINVER를 0x0400으로 정의하는 일을 한다. 만약 코드가 아래와 같이 되어 있다면 WINVER 값은 무엇이 될까?

 

#define WINVER 0x0500
#ifndef WINVER
#define WINVER 0x0400
#endif

위의 경우 #ifndef를 만나기 전에 WINVER가 정의되어 있기 때문에 #ifndef부터 #endif까지는 컴파일이 되지 않는다. 따라서 WINVER는 0x0500이 된다.

그렇다면, 이제 위에서 정의된 네 개의 상수가 어떤 의미를 가지는 것들인지 알아보도록 하자. 처음으로 나온 WINVER는 윈도우의 버전을 나타낸다. 즉, 어떤 버전 이상의 윈도우 플랫폼을 겨냥한 프로그램을 개발할지를 나타낸다고 생각하면 된다.

다음으로 나오는 _WIN32_WINNT의 경우는 윈도우NT계열의 운영체제의 버전을 나타낸다. NT 계열 운영체제로는 윈도우NT, 2000, XP, 2003등이 있다. _WIN32_WINDOWS는 9x 계열 운영체제의 버전을 나타낸다. 9x 계열의 운영체제로는 윈도우95, 98, ME가 있다. 마지막으로 나오는 _WIN32_IE는 인터넷 익스플로러의 버전을 나타낸다.

이러한 것들을 헤더에서 정의해 주는 이유는 사용할 API의 한계를 결정짓기 위해서다. 윈도우 API의 경우 새로운 운영체제가 나오거나, 새로운 인터넷 익스플로러가 출시될 때마다 추가되는 경향이 있다. 최신 운영체제에서만 지원하는 API를 사용한 경우 그 운영체제보다 아래의 버전에서는 해당 프로그램이 동작하지 않는다는 이야기다.

예를 들면 InterlockedExchangeAdd란 API는 윈도우 98부터 사용할 수 있다. 윈도우 95에는 해당 API가 존재하지 않는 것이다. 따라서 윈도우 95에서 동작하는 프로그램을 만든다면 위 API는 사용해서는 안 된다. 윈도우 API는 수천 가지도 넘게 존재하고 앞으로도 계속 추가될 것이다. 이러한 API 하나하나에 대한 지원정보를 프로그래머가 일일이 구분해서 사용한다는 것은 매우 힘든 일이다. 그래서 프로그램을 개발할 때에 위와 같은 매크로를 통해서 이 프로그램이 동작할 수 있는 하한선을 정의함으로써 그 보다 더 높은 시스템만 지원하는 API는 컴파일 시 포함되지 않게 하는 것이다. 이로써 프로그래머가 해당 시스템에선 사용할 수 없는 API를 쓰는 실수를 하게 된다면 컴파일러는 오류를 발생시켜 알려줄 수 있는 것이다.

플랫폼 버전 매크로
Windows “Longhorn” _WIN32_WINNT >= 0x0600 WINVER >= 0x0600
Windows Server 2003 _WIN32_WINNT >= 0x0502 WINVER >= 0x0502
Windows XP _WIN32_WINNT >= 0x0501 WINVER >= 0x0501
Windows 2000 _WIN32_WINNT >= 0x0500 WINVER >= 0x0500
Windows NT 4.0 _WIN32_WINNT >= 0x0400 WINVER >= 0x0400
Windows ME _WIN32_WINDOWS >= 0x0500 WINVER >= 0x0500
Windows 98 _WIN32_WINDOWS >= 0x0410 WINVER >= 0x0410
Windows 95 _WIN32_WINDOWS >= 0x0400 WINVER >= 0x0400
Internet Explorer 7.0 _WIN32_IE >= 0x0700
Internet Explorer 6.0 SP2 _WIN32_IE >= 0x0603
Internet Explorer 6.0 SP1 _WIN32_IE >= 0x0601
Internet Explorer 6.0 _WIN32_IE >= 0x0600
Internet Explorer 5.5 _WIN32_IE >= 0x0550
Internet Explorer 5.01 _WIN32_IE >= 0x0501
Internet Explorer 5.0, 5.0a, 5.0b _WIN32_IE >= 0x0500
Internet Explorer 4.01 _WIN32_IE >= 0x0401
Internet Explorer 4.0 _WIN32_IE >= 0x0400
Internet Explorer 3.0, 3.01, 3.02 _WIN32_IE
@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중