2 minute read

K.N.KING C PROGRAMMING A Modern Approach

Chapter 14 PART 1

14.4 Conditional Compilation

Conditional compilation을 통해 preprocessor이 프로그램의 특정 부분을 포함시키거나, 제외시킬 수 있다.

#if, #endif

우리가 프로그램을 디버깅 중에 있다고 생각해 보자.
특정 부분에서 디버깅을 위해 printf문을 넣었다. 디버깅이 끝난 후에 생각해 보니 이 printf문이 나중에도 유용하게 쓰일 수 있을 것 같다. 그냥 주석 처리를 해도 되지만, 다시 디버깅을 할 때 일일히 주석을 해제하려면 무척 귀찮고 실수할 여지도 많을 것이다.
이럴 때 유용한 것이 #if#endif directive이다. 사용 예시를 살펴보자.

#define DEBUG 1

...

#if DEBUG
printf("Value of i: %d\n", i);
printf("Value of j: %d\n", j);
#endif

문법 구조는 #if constant-expression 이다. Preprocessor는 전처리 과정 중에 #if를 발견하면 그 다음에 있는 특정 값을 확인한다. 이 값이 참(즉, 0이 아닌 값)이면 preprocessor는 #if DEBUG#endif가 있는 줄만 지워주고, 그 사이에 있는 부분은 남겨 둔다. 반대로 #if 뒤의 값이 거짓, 즉 0이면 preprocessor는 #if DEBUG부터 #endif까지 모든 텍스트를 지워 버리고 object code를 만들어 컴파일러에게 넘겨 준다.
우리는 이제 디버깅을 하고 싶을 때, DEBUG 매크로를 0에서 1로 바꿔 주기만 하면 된다. 디버깅을 끝내고 싶으면 DEBUG를 0으로 다시 되돌려 주면 된다.
정의되지 않은 값이 #if 뒤에 나오면, preprocessor는 거짓인 것으로 판단한다. 또, DEBUG가 정의되지 않은 상태에서 #if !DEBUG를 하면 참으로 판단한다.

defined

#와 ##에 이어 세 번째로 만나는 preprocessor에게 의미 있는 operator가 defined이다.앞에서 #if는 그 값을 기준으로 판단했다면, defined는 값이 정의되었으면 1, 정의되지 않았으면 0을 만들어 내는 operator이다.

#if defined(DEBUG)
...
#endif

위와 같이 #if와 합쳐져 주로 쓰이게 된다. 그리고 DEBUG 자체의 값을 필요로 하지 않기 때문에 #DEFINE DEBUG로만 매크로를 정의해 줘도 동작한다.

#ifdef, ```#ifndef`

위의 #ifdefif defined(DEBUG)와 정확히 같다. #ifndef#ifdef의 반대로, 정의되지 않았을 때만 해당 코드 블럭을 포함시킨다.
#ifndef#if !defined(DEBUG)와 같다.

#ifdef DEBUG
...
...
#endif

#ifdef#endif 사이의 코드는 DEBUG의 정의 여부에 따라 preprocessor에 의해 object code에 포함되거나 제외된다.

#elif, #else

우리가 아는 if-else문처럼 이 directive들도 비슷하게 사용할 수 있다.

#if expr1
/* expr1이 참이면 포함, 거짓이면 제외 */
#elif expr2
/* expr1이 거짓일 때 expr2가 참이면 포함, expr2가 거짓이면 제외 */
#else
/* expr1과 expr2 모두 거짓일 때 포함 */
#endif

#if 뿐만 아니라 #ifdef#ifndef도 물론 위와 같은 형식으로 쓸 수 있다.

Uses of Conditional Compilation

Conditional compilation의 용도는 디버깅 외에도 여럿 있다.

  1. 여러 종류의 machine이나 OS에서 portable하게 사용되는 프로그램 작성하기
    #ifdef WIN32
    /* 윈도우 운영체제인 경우의 코드 */
    #elif MAC_OS
    /* 맥 운영체제인 경우의 코드 */
    #elif LINUX
    /* 리눅스 운영체제인 경우의 코드 */
    ...
    #endif
    
  2. 여러 컴파일러에 의해 컴파일 될 프로그램 작성하기 __STDC__ 매크로는 해당 컴파일러가 표준 규격과 호환되면 1이다.
    #if __STCD__
    /* 일반적인 function prototype */
    #else
    /* Old-style 함수 */
    
  3. 특정 매크로 초기값 설정
    #ifndef BUFFER_SIZE
    #define BUFFER_SIZE 256
    #endif
    

    특정 매크로가 정의되지 않았을 때, 정의해 주면서 동시에 초기값도 설정해 줄 수 있다.

  4. 헤더 파일 관련 이 부분은 15장에서 다루게 된다.

14.5 Miscellaneous Directives

#error

#error message

위와 같이 사용한다. 컴파일러는 #error를 만나면 해당 메시지를 출력하고, 컴파일러에 따라 컴파일을 중단하기도 한다.
주로 프로그램의 serious flaw를 찾기 위해 사용된다. 16비트 머신이라 INT_MAX가 100,000 미만이라던가, OS가 설정되지 않았거나(위 1번에서 마지막 #else에 들어갈 수 있다), 이런 경우에 즉시 컴파일을 중단하고 에러 메시지를 띄우도록 사용할 수 있다.

#line, pragma

얘네는 몰라도 될 것 같다.

Tags:

Categories:

Updated: