Conditional inclusion
전처리기는 소스 파일의 일부를 조건부로 컴파일하는 기능을 지원합니다. 이 동작은
#if
,
#else
,
#elif
,
#ifdef
,
#ifndef
,
#elifdef
,
#elifndef
(C++23부터)
, 그리고
#endif
지시문에 의해 제어됩니다.
목차 |
구문
#if
표현식
|
|||||||||
#ifdef
식별자
|
|||||||||
#ifndef
식별자
|
|||||||||
#elif
표현식
|
|||||||||
#elifdef
식별자
|
(C++23부터) | ||||||||
#elifndef
식별자
|
(C++23부터) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
설명
조건부 전처리 블록은
#if
,
#ifdef
또는
#ifndef
지시자로 시작하며, 선택적으로 임의의 수의
#elif
,
#elifdef
, 또는
#elifndef
(C++23부터)
지시자를 포함할 수 있고, 선택적으로 최대 하나의
#else
지시자를 포함하며,
#endif
지시자로 종료됩니다. 내부 조건부 전처리 블록은 별도로 처리됩니다.
다음 각 지시문들
#if
,
#ifdef
,
#ifndef
,
#elif
,
#elifdef
,
#elifndef
(C++23부터)
, 그리고
#else
는 첫 번째
#elif
,
#elifdef
,
#elifndef
(C++23부터)
,
#else
,
#endif
지시문이 나타날 때까지의 코드 블록을 제어합니다. 단, 내부 조건부 전처리 블록에 속하지 않는 지시문까지입니다.
#if
,
#ifdef
및
#ifndef
지시자는 지정된 조건(아래 참조)을 검사하고 조건이 true로 평가되면 제어되는 코드 블록을 컴파일합니다. 이 경우 후속
#else
,
#elifdef
,
#elifndef
,
(C++23 이후)
및
#elif
지시자는 무시됩니다. 반면에 지정된 조건이 false로 평가되면 제어되는 코드 블록은 건너뛰고 후속
#else
,
#elifdef
,
#elifndef
,
(C++23 이후)
또는
#elif
지시자(존재하는 경우)가 처리됩니다. 후속 지시자가
#else
인 경우,
#else
지시자에 의해 제어되는 코드 블록은 무조건 컴파일됩니다. 그렇지 않으면
#elif
,
#elifdef
, 또는
#elifndef
(C++23 이후)
지시자는 마치
#if
지시자인 것처럼 동작합니다: 조건을 검사하고 결과에 따라 제어되는 코드 블록을 컴파일하거나 건너뛰며, 후자의 경우 후속
#elif
,
#elifdef
,
#elifndef
,
(C++23 이후)
및
#else
지시자를 처리합니다. 조건부 전처리 블록은
#endif
지시자로 종료됩니다.
조건 평가
#if, #elif
expression
은
defined
identifier
또는
defined (
identifier
)
형태의 단항 연산자를 포함할 수 있습니다. 결과는
identifier
가
매크로 이름으로 정의되었을 경우
1
이고, 그렇지 않을 경우 결과는
0
입니다.
|
expression 은 다음 표현들도 포함할 수 있습니다:
위에서 언급된 식별자들은 이 컨텍스트에서 정의된 매크로 이름처럼 취급됩니다. |
(since C++17) |
모든 매크로 확장과 위에서 설명한
defined
및 표현식 평가 후에,
boolean literal
가 아닌 모든 식별자는 숫자
0
로 대체됩니다
(여기에는 어휘적으로 키워드이지만
and
와 같은 대체 토큰은 아닌 식별자들이 포함됩니다).
그러면 해당 표현식은 integral constant expression 으로 평가됩니다.
만약 expression 이 0이 아닌 값으로 평가되면, 제어되는 코드 블록이 포함되고 그렇지 않으면 건너뜁니다.
참고:
CWG 이슈 1955
가 해결되기 전까지,
#if
cond1
...
#elif
cond2
는
#if
cond1
...
#else
뒤에
#if
cond2
가 오는 경우와 다릅니다. 왜냐하면
cond1
가 참일 경우, 두 번째
#if
는 건너뛰어지고
cond2
는 올바른 형식일 필요가 없지만,
#elif
의
cond2
는 유효한 표현식이어야 하기 때문입니다. CWG 1955에 따르면, 건너뛰어지는 코드 블록을 이끄는
#elif
도 건너뛰어집니다.
결합 지시문
식별자가 매크로 이름으로 정의되었는지 확인합니다.
#ifdef
identifier
는 기본적으로
#if defined
identifier
와 동일합니다.
#ifndef
identifier
는 기본적으로
#if !defined
identifier
와 동등합니다.
|
|
(C++23부터) |
참고 사항
#elifdef
와
#elifndef
지시문은 C++23을 대상으로 하지만, 구현체들은 이를 이전 언어 모드로 역호환되는 확장 기능으로 백포트하는 것이 권장됩니다.
예제
#define ABCD 2 #include <iostream> int main() { #ifdef ABCD std::cout << "1: yes\n"; #else std::cout << "1: no\n"; #endif #ifndef ABCD std::cout << "2: no1\n"; #elif ABCD == 2 std::cout << "2: yes\n"; #else std::cout << "2: no2\n"; #endif #if !defined(DCBA) && (ABCD < 2*4-3) std::cout << "3: yes\n"; #endif // C++23의 #elifdef/#elifndef 지시자를 지원하지 않는 컴파일러인 경우 // "예상치 못한" 블록(아래 참조)이 선택됩니다. #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // 예상 블록 #else std::cout << "4: no!\n"; // 알 수 없는 지시자를 건너뛰고 "#ifdef CPU"에서 // 직접 이 "#else" 블록으로 "점프"하여 // 예상치 못하게 이 블록을 선택함 #endif // 위 문제를 해결하기 위해 C++23 지시자 #elifdef/#elifndef가 // 지원되는 경우에만 매크로 ELIFDEF_SUPPORTED를 조건부로 정의할 수 있습니다. #if 0 #elifndef UNDEFINED_MACRO #define ELIFDEF_SUPPORTED #else #endif #ifdef ELIFDEF_SUPPORTED #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // 예상 블록 #else std::cout << "4: no3\n"; #endif #else // #elifdef가 지원되지 않을 때는 기존의 장황한 "#elif defined" 사용 #ifdef CPU std::cout << "4: no1\n"; #elif defined GPU std::cout << "4: no2\n"; #elif !defined RAM std::cout << "4: yes\n"; // 예상 블록 #else std::cout << "4: no3\n"; #endif #endif }
가능한 출력:
1: yes 2: yes 3: yes 4: no! 4: yes
결함 보고서
다음 동작 변경 결함 보고서는 이전에 게시된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 1955 | C++98 | 실패한 #elif 표현식이 유효해야 했음 | 실패한 #elif 은 건너뜀 |
참고 항목
|
C 문서
참조:
조건부 포함
|