C PreProcessor

프로그래머가 작성한 C 소스코드에는 전처리기 지시자 ( directives ), 사용자 정의 매크로가 포함되어 있기 때문에 먼저 전처리 과정을 거친 후에 최종 결과가 컴파일러에 전달됩니다.

  • 파일을 include 할 때 사용하는 #include

  • 매크로를 정의하거나 해제할 때 사용하는 #define #undef

  • 선택적으로 특정 코드를 제외하거나 포함할 때 사용하는 #if(n)def #if #else #elif #endif

  • Diagnostic 메시지와 flow control 에 사용되는 #error #warning

  • Line control 에 사용되는 #line

  • 일종의 확장 지시자 #pragma

전처리기 지시자는 # 문자로 시작하는데 사이에 공백을 여러개 두어도 됩니다.

# if defined(__BIG_ENDIAN)                           // #if
#       define AFMT_S16_NE AFMT_S16_BE               // #define
#   elif defined(__LITTLE_ENDIAN)                    // #elif
#       define AFMT_S16_NE AFMT_S16_LE               // #define
#   else                                             // #else
#       error "could not determine byte order"       // #error
# endif                                              // #endif

C++ 템플릿도 확장 결과가 소스코드가 된다는 점에서 보면 매크로와 비슷한데 템플릿은 처리 과정에서 syntatic, semantic 체크도 하는 반면에 매크로는 단순 lexical 치환입니다. 그렇다고 매크로가 C/C++ 문법에서 완전히 자유로운 것은 아니고 가령 quotes 을 사용할 경우는 " or ' 의 balance 가 맞아야 하고 ## 연산자를 이용해 두 token 을 결합할 경우는 결과가 적합한 전처리기 token 이 되어야 합니다.

예를 들어 =+ 를 결합하면 =+ 가 되는데 이것은 적합한 전처리기 token 이 아닙니다.

매크로와 비슷한 기능으로 enum 이 있는데 enum 은 compile-time 에 처리되는 기능으로 사용자 타입도 지정할 수 있고, scope 도 가질 수 있습니다. 원래 C 언어에서는 매크로만 사용하였는데 나중에 enum 이 추가되었다고 합니다.

매크로의 특징

매크로의 특징은 단순 텍스트 프로세싱이라는 점입니다. 예를 들어 프로그래밍 언어에서는 NUM 이라는 변수에 10 을 대입한 후에 INC ( increment ) 하면 11 이 되지만 매크로에서는 INC 한 결과를 얻으려면 다음과 같이 직접 모든 결과값에 대해 매크로 정의를 해주어야 합니다. ( 매크로를 다룰 때는 약간 발상의 전환이 필요합니다. )

$ gcpp                                 $ gcpp
#define JOIN(x, y) x ## y              #define JOIN(x, y) x ## y
#define INC(x) JOIN(INC_, x)           #define DEC(x) JOIN(DEC_, x)
#define INC_0 1                        #define DEC_1 0
#define INC_1 2                        #define DEC_2 1
#define INC_2 3                        #define DEC_3 2      // 직접 모든 결과값에 대해
#define INC_3 4                        #define DEC_4 3      // 매크로 정의를 해주어야 한다.
#define INC_4 5                        #define DEC_5 4

INC(3)                                 DEC(3)
@                                      @

4        // 결과                        2        // 결과
-------------------------------------------------------

1. INC(3)         ---->   JOIN(INC_, 3)
2. JOIN(INC_, 3)  ---->   INC_3
3. INC_3          ---->   4

매크로 테스트에 사용되는 gcpp 명령

본문 전체에 걸쳐 매크로 테스트에 gcpp 명령이 사용되는데 이것은 다음과 같은 bash shell alias 입니다.

$ alias gcpp='gcc -E -P - <<\@'

# -P 옵션을 사용하면 매크로 확장시 다음과 같은 linemarkers 가 출력되지 않습니다.

# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
. . .

CPP 메뉴얼 주소

https://gcc.gnu.org/onlinedocs/cpp/