Spec-Zone.ru › C

Условное включение

Предпроцессор поддерживает условную компиляцию частей исходного файла. Это поведение контролируется директивами #if, #else, #elif, #ifdef, #ifndef, #elifdef, #elifndef(с C23), и #endif.

Синтаксис

#if выражение
#ifdef идентификатор
#ifndef идентификатор
#elif выражение
#elifdef идентификатор (с C23)
#elifndef идентификатор (с C23)
#else
#endif

Объяснение

Блок условной предобработки начинается с директивы #if, #ifdef или #ifndef, затем необязательно включает любое количество директивы #elif, #elifdef, или #elifndef(с C23), затем необязательно включает не более одной директивы #else и завершается директивой #endif. Любые внутренние блоки условной предобработки обрабатываются отдельно.

Каждая из директивы #if, #ifdef, #ifndef, #elif, #elifdef, #elifndef(с C23), и #else контролирует блок кода до первой директивы #elif, #elifdef, #elifndef(с C23), #else, #endif не принадлежащей никаким внутренним блокам условной предобработки.

Директивы #if, #ifdef и #ifndef проверяют указанное условие (см. ниже), и если оно истинно, компилируют управляемый блок кода. В этом случае последующие директивы #else, #elifdef, #elifndef,(с C23) и #elif игнорируются. В противном случае, если указанное условие ложно, управляемый блок кода пропускается, и обрабатывается последующая директива #else, #elifdef, #elifndef,(с C23) или #elif (если есть). Если последующая директива #else, блок кода, управляемый директивой #else, компилируется безусловно. В противном случае, директива #elif, #elifdef, или #elifndef(с C23) действует так, как если бы это была директива #if: проверяет условие, компилирует или пропускает управляемый блок кода в зависимости от результата, и в последнем случае обрабатывает последующие директивы #elif, #elifdef, #elifndef,(с C23) и #else директивы. Блок условной предобработки завершается директивой #endif.

Условная проверка

#if, #elif

Выражение выражение является константным выражением, использующим только константы и идентификаторы, определенные с помощью директивы #define. Любой идентификатор, который не является литералом и не определен с помощью директивы #define, оценивается как ​0​ за исключением true, которое оценивается как 1(с C23).

Выражение может содержать унарные операторы в форме defined идентификатор или defined (идентификатор), которые возвращают 1, если идентификатор был определен с помощью директивы #define, и ​0​ в противном случае. В этом контексте __has_include, __has_embed и __has_c_attribute обрабатываются так, как если бы они были именами определенных макросов.(с C23) Если выражение оценивается как ненулевое значение, управляемый блок кода включается, в противном случае пропускается. Если какой-либо использованный идентификатор не является константой, он заменяется на ​0​.

В контексте директивы препроцессора выражение __has_c_attribute определяет, поддерживается ли данный атрибутный токен и его поддерживаемая версия. См. Проверка атрибутов.

(с C23)

Примечание: До DR 412, #if cond1 ... #elif cond2 отличается от #if cond1 ... #else за которым следует #if cond3, потому что если cond1 истинно, то второе #if пропускается, и cond3 не обязательно должно быть правильно сформированным, тогда как #elif's cond2 должно быть корректным выражением. С DR 412, #elif , ведущее пропускаемый блок кода, также пропускается.

Объединенные директивы

Проверяет, был ли идентификатор определен как имя макроса.

#ifdef идентификатор по существу эквивалентно #if defined идентификатор.

#ifndef идентификатор по существу эквивалентно #if !defined идентификатор.

#elifdef идентификатор по существу эквивалентно #elif defined идентификатор.

#elifndef идентификатор по существу эквивалентно #elif !defined идентификатор.

(с C23)

Примечания

Хотя директивы #elifdef и #elifndef предназначены для C23, реализации могут их перенести в более старые режимы языка как согласующиеся расширения.

Пример

#define ABCD 2
#include <stdio.h>
 
int main(void)
{
 
#ifdef ABCD
    printf("1: yes\n");
#else
    printf("1: no\n");
#endif
 
#ifndef ABCD
    printf("2: no1\n");
#elif ABCD == 2
    printf("2: yes\n");
#else
    printf("2: no2\n");
#endif
 
#if !defined(DCBA) && (ABCD < 2 * 4 - 3)
    printf("3: yes\n");
#endif
 
// C23 directives #elifdef/#elifndef
#ifdef CPU
    printf("4: no1\n");
#elifdef GPU
    printf("4: no2\n");
#elifndef RAM
    printf("4: yes\n"); // selected in C23 mode, may be selected in pre-C23 mode
#else
    printf("4: no3\n"); // may be selected in pre-C23 mode
#endif
}

Возможный вывод:

1: yes
2: yes
3: yes
4: yes

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C.

DR Применено к Поведение, как опубликовано Корректное поведение
DR 412 C89 проверка #elif требовалось, чтобы выражение было корректным проверка #elif пропускается

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2023):
    • 6.10.1 Условное включение (стр: TBD)
  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.10.1 Условное включение (стр: 118-119)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.10.1 Условное включение (стр: 162-164)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.10.1 Условное включение (стр: 147-149)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.8.1 Условное включение

См. также

Документация C++ по Условному включению

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/preprocessor/conditional

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API