Условное включение
Предпроцессор поддерживает условную компиляцию частей исходного файла. Это поведение контролируется директивами #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.
| В контексте директивы препроцессора выражение | (с 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 идентификатор.
|
| (с 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