Namespaces
Variants

Conditional inclusion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Preprocessor
#if #ifdef #ifndef #else #elif #elifdef #elifndef #endif
(C++23) (C++23)
(C++26)

전처리기는 소스 파일의 일부를 조건부로 컴파일하는 기능을 지원합니다. 이 동작은 #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 은 다음 표현들도 포함할 수 있습니다:

  • __has_include 표현식 - 헤더나 소스 파일이 존재하는지 감지합니다.
  • __has_cpp_attribute 표현식 - 주어진 속성 토큰이 지원되는지와 지원되는 버전을 감지합니다.
(since C++20)
  • __has_embed 표현식 - 임베드할 수 있는 리소스가 사용 가능한지 감지합니다.
(since C++26)

위에서 언급된 식별자들은 이 컨텍스트에서 정의된 매크로 이름처럼 취급됩니다.

(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 와 동등합니다.

#elifdef identifier 는 본질적으로 #elif defined identifier 와 동등합니다.

#elifndef identifier 는 본질적으로 #elif !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 문서 참조: 조건부 포함