Постоянные выражения
Несколько разновидностей выражений известны как постоянные выражения
Выражение препроцессора
Выражение, следующее за #if или #elif, должно быть расширено до
- операторов , кроме присваивания, инкремента, декремента, вызова функции или запятой, аргументы которых являются выражениями препроцессора;
- целых констант
- символьных констант
- специального оператора препроцессора
defined
Символьные константы, при вычислении в выражениях #if, могут интерпретироваться в наборе символов исходного файла, наборе символов выполнения или в другом наборе символов, определённом реализацией.
| Целочисленная арифметика в выражениях | (с C99) |
Целочисленное постоянное выражение
Целочисленное постоянное выражение — это выражение, состоящее только из
- операторов, кроме присваивания, инкремента, декремента, вызова функции или запятой, за исключением того, что операторы преобразования типов могут преобразовывать только арифметические типы в целочисленные типы, если они не являются частью операнда операторов sizeof, _Alignof(с C11) или typeof/typeof_unqual(с C23).
- целых констант
- перечислений
- символьных констант
- вещественных констант, но только если они немедленно используются в качестве операндов преобразований в целочисленный тип
- операторов
sizeofнад операндами, которые не являются VLA(с C99)
| (с C11) |
| (с C23) |
Целочисленные постоянные выражения вычисляются во время компиляции. Следующие контексты требуют выражений, которые известны как целочисленные постоянные выражения:
- Размер битового поля.
- Значение перечисления
- Метка
caseоператора switch - Размер массива без VLA(с C99)
- Неявное преобразование целого числа в указатель.
| (с C99) |
| (с C11) |
| (с C23) |
Статическая инициализация
Выражения, используемые в инициализаторах объектов со статической и thread_local длительностью хранения или объявленных с спецификатором класса хранения constexpr(с C23) должны быть либо строковыми литералами, либо выражениями, которые могут быть одним из следующих
- операторов, кроме присваивания, инкремента, декремента, вызова функции или запятой, за исключением того, что операторы преобразования типов должны преобразовывать арифметические типы в другие арифметические типы, если они не являются частью операнда операторов sizeof, _Alignof(с C11) или typeof/typeof_unqual(с C23)
- целых констант
- вещественных констант
- перечислений
- символьных констант
- операторов
sizeofнад операндами, которые не являются VLA(с C99)
| (с C11) |
| (с C23) |
NULL)- нулевой указатель
- lvalue обозначающее объект со статической длительностью хранения или указатель на функцию, преобразованный в указатель либо
- с использованием унарного оператора взятия адреса
- посредством преобразования целочисленной константы в указатель
- посредством неявного преобразования массива в указатель или функции в указатель
5) именованная константа, которая является идентификатором, который
. к именованной константе структуры или объединения, даже рекурсивно. 6) константа составного литерала, которая
Константа структуры или объединения — это именованная константа или составная константа литерала со структурой или объединением типа, соответственно. Если оператор доступа к члену | (с C23) |
В отличие от целочисленных постоянных выражений, выражения статической инициализации не обязаны вычисляться во время компиляции; компилятор имеет право преобразовать такие инициализаторы в выполняемый код, который вызывается до запуска программы.
static int i = 2 || 1 / 0; // initializes i to value 1
Значение вещественного статического инициализатора никогда не менее точное, чем значение того же выражения, выполненного во время выполнения, но может быть лучше.
Вещественные постоянные выражения
Арифметические постоянные выражения вещественных типов, которые не используются в статических инициализаторах, всегда вычисляются так, как если бы они выполнялись во время выполнения, и на них влияет текущий способ округления (если FENV_ACCESS включен) и сообщают об ошибках, как указано в math_errhandling.
void f(void)
{
#pragma STDC FENV_ACCESS ON
static float x = 0.0/0.0; // static initializer: does not raise an exception
float w[] = { 0.0/0.0 }; // raises an exception
float y = 0.0/0.0; // raises an exception
double z = 0.0/0.0; // raises an exception
}Примечания
Если выражение вычисляется в значение, которое не может быть представлено его типом, оно не может использоваться как константное выражение.
Реализации могут принимать другие формы константных выражений. Однако эти константные выражения не рассматриваются как целочисленные константные выражения, арифметические константные выражения или адресные константные выражения и, следовательно, не могут использоваться в контекстах, требующих этих видов константных выражений. Например, int arr[(int)+1.0]; объявляет VLA.
Ссылки
- Стандарт C23 (ISO/IEC 9899:2023):
- 6.6 Константные выражения (с. TBD)
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.6 Константные выражения (с. 76-77)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.6 Константные выражения (с. 106-107)
- Стандарт C99 (ISO/IEC 9899:1999):
- 6.6 Константные выражения (с. 95-96)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
- 3.4 КОНСТАНТНЫЕ ВЫРАЖЕНИЯ
См. также
| Документация C++ по Константным выражениям |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/constant_expression