Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 전처리기 완벽 가이드: #define부터 조건부 컴파일까지

C++ 전처리기란?

전처리기(preprocessor)는 실제 컴파일이 시작되기 전에 소스 코드를 사전 처리하도록 컴파일러에 지시하는 명령어입니다. 헤더 파일 포함, 매크로 확장, 조건부 컴파일 등의 작업을 담당합니다.

모든 전처리기 지시문은 # 기호로 시작하며, 한 줄에서 지시문 앞에는 공백 문자만 위치할 수 있습니다. 또한 전처리기 지시문은 C++ 문(statement)이 아니기 때문에 세미콜론(;)으로 끝내지 않습니다.

지금까지 살펴본 예제에서 이미 #include 지시문을 접해 보셨을 것입니다. 이 지시문은 헤더 파일을 소스 파일에 포함시키는 역할을 합니다.

C++에서 지원하는 대표적인 전처리기 지시문으로는 #include, #define, #if, #else, #endif, #ifdef, #ifndef, #undef, #line, #pragma 등이 있습니다. 지금부터 핵심 지시문들을 하나씩 살펴보겠습니다.

#define - 매크로 상수 정의

#define 지시문은 심볼릭 상수(symbolic constant)를 생성합니다. 이렇게 정의된 이름을 매크로(macro)라고 부르며, 기본 형식은 다음과 같습니다.

#define 매크로이름 치환텍스트

컴파일 전에 코드에 등장하는 매크로 이름이 모두 치환 텍스트로 바뀝니다. 원주율처럼 자주 사용되는 값을 매크로로 정의하면 코드의 가독성과 유지보수성이 크게 향상됩니다.

예제 코드

#include <iostream>
using namespace std;

#define PI 3.14159

int main () {
    cout << "Value of PI :" << PI << endl;
    return 0;
}

실행 결과

Value of PI :3.14159

함수형 매크로(Function-like Macro)

#define은 단순 상수 외에도 인자를 받는 함수형 매크로를 정의할 수 있습니다. 아래 매크로는 두 값 중 작은 값을 반환합니다.

#define MIN(a,b) (((a)<(b)) ? a : b)

함수형 매크로는 함수 호출 오버헤드 없이 동작하지만, 인자에 증감 연산 같은 부작용이 있으면 의도와 다른 결과가 나올 수 있습니다. 따라서 위 예제처럼 각 인자와 전체를 괄호로 감싸 안전하게 정의하는 것이 좋습니다.

조건부 컴파일(Conditional Compilation)

전처리기를 활용하면 프로그램 소스 코드 중 필요한 부분만 선택적으로 컴파일할 수 있습니다. 이를 조건부 컴파일이라고 하며, 그 구조는 일반적인 if 선택문과 매우 유사합니다.

NULL 정의 여부 검사

#ifndef NULL
    #define NULL 0
#endif

#ifndef는 지정한 매크로가 아직 정의되지 않았을 때만 블록 내부를 처리합니다. 위 코드는 NULL이 정의되어 있지 않으면 0으로 정의합니다.

디버깅 코드 켜고 끄기

DEBUG 매크로를 정의하거나 삭제하는 것만으로 디버깅 출력을 손쉽게 on/off 할 수 있습니다.

#ifdef DEBUG
cerr <<"Variable x = " << x << endl;
#endif

#ifdef DEBUG 지시문 이전에 DEBUG 심볼릭 상수가 정의되어 있다면, cerr 문이 컴파일에 포함됩니다.

코드 블록 통째로 비활성화

#if 0 ... #endif 구문을 사용하면 여러 줄의 코드를 주석 처리한 것처럼 간단히 비활성화할 수 있습니다. /* */ 주석과 달리 중첩된 주석 블록에도 안전하게 사용할 수 있다는 장점이 있습니다.

#if 0
    컴파일에서 제외되는 코드
#endif

종합 예제

지금까지 배운 내용을 모두 활용한 예제입니다.

예제 코드

#include <iostream>
using namespace std;
#define DEBUG

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
    int i, j;
    i = 100;
    j = 30;

    #ifdef DEBUG
        cerr <<"Trace: Inside main function" << endl;
    #endif

    #if 0
        /* This is commented part */
        cout << MKSTR(HELLO C++) << endl;
    #endif

    cout <<"The minimum is " << MIN(i, j) << endl;

    #ifdef DEBUG
        cerr <<"Trace: Coming out of main function" << endl;
    #endif

    return 0;
}

실행 결과

Trace: Inside main function
The minimum is 30
Trace: Coming out of main function

DEBUG 매크로가 정의되어 있어 추적 메시지가 함께 출력되었고, #if 0 블록 안의 코드는 컴파일되지 않아 실행 결과에 나타나지 않습니다. #define DEBUG 한 줄을 삭제하고 다시 컴파일하면 추적 메시지 없이 최솟값만 출력됩니다.