76.2 값 또는 식으로 조건부 컴파일하기
이번에는 #if로 값 또는 식을 판별하여 조건부 컴파일을 해보겠습니다.
#if 값 또는 식 코드 #endif
다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.
conditional_compile_expression.c
#include <stdio.h> #define DEBUG_LEVEL 2 // 2를 DEBUG_LEVEL로 정의 int main() { #if DEBUG_LEVEL >= 2 // DEBUG_LEVEL이 2보다 크거나 같으면 #if, #endif 사이의 코드를 컴파일 printf("Debug Level 2\n"); #endif #if 1 // 조건이 항상 참이므로 #if, #endif 사이의 코드를 컴파일 printf("1\n"); #endif #if 0 // 조건이 항상 거짓이므로 #if, #endif 사이의 코드를 컴파일하지 않음 printf("0\n"); #endif return 0; }
실행 결과
Debug Level 2 1
이번에는 2를 DEBUG_LEVEL 매크로로 정의했습니다. 그리고 #if DEBUG_LEVEL >= 2와 같이 정의했으므로 DEBUG_LEVEL이 2보다 크거나 같을 때 코드를 컴파일합니다.
#if DEBUG_LEVEL >= 2 // DEBUG_LEVEL이 2보다 크거나 같으면 #if, #endif 사이의 코드를 컴파일 printf("Debug Level 2\n"); #endif
#if에는 값을 그대로 지정할 수도 있습니다. 여기서 1을 지정하면 조건이 항상 참이므로 코드를 컴파일하고, 0을 지정하면 조건이 항상 거짓이므로 코드를 컴파일하지 않습니다.
#if 1 // 조건이 항상 참이므로 #if, #endif 사이의 코드를 컴파일 printf("1\n"); #endif #if 0 // 조건이 항상 거짓이므로 #if, #endif 사이의 코드를 컴파일하지 않음 printf("0\n"); #endif
#if, #endif는 전처리기 과정을 거치면 코드는 다음과 같이 바뀝니다.
#if는 defined와 조합하면 복잡한 조건도 만들 수 있습니다.
#if defined 매크로 코드 #endif
다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.
conditional_compile_logical_operator.c
#include <stdio.h> #define DEBUG // DEBUG 매크로 정의 #define TEST // TEST 매크로 정의 int main() { // DEBUG 또는 TEST가 정의되어 있으면서 VERSION_10이 정의되어 있지 않을 때 #if (defined DEBUG || defined TEST) && !defined (VERSION_10) printf("Debug\n"); #endif return 0; }
실행 결과
Debug
#if defined에는 논리 연산자를 사용할 수 있습니다. 여기서는 DEBUG 또는(||) TEST가 정의되어 있으면서(&&) VERSION_10이 정의되어 있지 않을 때(!) 코드를 컴파일합니다.
#if (defined DEBUG || defined TEST) && !defined (VERSION_10) printf("Debug\n"); #endif
defined 뒤의 괄호는 생략해도 됩니다. 그리고 논리 연산의 순서를 명확하게 나타내기 위해 defined와 논리 연산자를 모두 괄호로 묶습니다.
#if는 다음과 같이 DEBUG 매크로를 정의해서 사용합니다. #define DEBUG 1과 같이 코드에서 1과 0을 지정하여 디버그 코드의 사용 여부를 제어하거나, 컴파일 옵션에서 DEBUG 매크로를 설정하여 디버그 코드를 제어합니다.
- Visual Studio: 솔루션 탐색기에서 프로젝트 선택 > 메인 메뉴의 프로젝트(P) > 속성(P) > C/C++ > 전처리기 > 전처리기 정의
- GCC: -D매크로이름, -D매크로이름=값
$ gcc main.c -DDEBUG $ gcc main.c -DDEBUG_LEVEL=2
#define DEBUG 1 // 코드에서 디버그 코드 제어 #if DEBUG printf("Debug message\n"); #endif #ifdef DEBUG // 코드에 DEBUG 매크로를 정의하거나 컴파일 옵션에서 DEBUG 매크로 설정 printf("Debug message\n"); #endif // 코드에서 2를 DEBUG_LEVEL 정의하거나 컴파일 옵션에서 DEBUG_LEVEL에 2를 설정 #ifdef DEBUG_LEVEL >= 2 printf("Debug Level 2\n"); #endif
이번에는 #elif와 #else를 사용해보겠습니다.
#ifdef 매크로 코드 #elif defined 매크로 코드 #else 코드 #endif #if 조건식 코드 #elif 조건식 코드 #else 코드 #endif
다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요
conditional_compile_elif_else.c
#include <stdio.h> #define USB // USB 매크로 정의 int main() { #ifdef PS2 // PS2가 정의되어 있을 때 코드를 컴파일 printf("PS2\n"); #elif defined USB // PS2가 정의되어 있지 않고, USB가 정의되어 있을 때 코드를 컴파일 printf("USB\n"); #else // PS2와 USB가 정의되어 있지 않을 때 코드를 컴파일 printf("지원하지 않는 장치입니다.\n"); #endif return 0; }
실행 결과
USB
#elif를 사용하여 PS2가 정의되어 있지 않고, USB가 정의되어 있을 때 코드를 컴파일하고, #else를 사용하여 PS2와 USB 둘 다 정의되어 있지 않을 때 코드를 컴파일하도록 만들었습니다. 여기서는 USB만 정의되어 있으므로 #elif defined USB만 만족합니다.
#ifdef PS2 // PS2가 정의되어 있을 때 코드를 컴파일 printf("PS2\n"); #elif defined USB // PS2가 정의되어 있지 않고, USB가 정의되어 있을 때 코드를 컴파일 printf("USB\n"); #else // PS2와 USB가 정의되어 있지 않을 때 코드를 컴파일 printf("지원하지 않는 장치입니다.\n"); #endif
#elif로 매크로를 판별할 때는 defined와 함께 사용해야 합니다.
#ifdef, #elif, #else가 전처리기 과정을 거치면 코드는 다음과 같이 바뀝니다.
#ifndef는 매크로가 정의되어 있지 않을 때 코드를 컴파일합니다.
#ifndef 매크로 코드 #endif
다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.
conditional_compile_undefined.c
#include <stdio.h> #define NDEBUG // NDEBUG 매크로 정의 int main() { #ifndef DEBUG // DEBUG가 정의되어 있지 않을 때 코드를 컴파일 printf("main function\n"); #endif return 0; }
실행 결과
main function
여기서는 NDEBUG만 정의되어 있고 DEBUG는 정의되어 있지 않습니다. 따라서 #ifndef DEBUG를 만족하므로 코드를 컴파일 합니다. 참고로 NDEBUG는 "not debug"를 뜻합니다.
#ifndef도 #elif, #else와 함께 사용할 수 있습니다.