Константные выражения
Известно несколько разновидностей выражений, называемых константными выражениями
Константное выражение препроцессора
Выражение после #if или #elif должно после подстановки состоять из
- операторов, отличных от присваивания, инкремента и декремента, вызова функции или оператора запятая, аргументами которых являются константные выражения препроцессора
- целочисленных констант
- символьных констант
- специального оператора препроцессора
defined
При вычислении в выражениях #if символьные константы могут интерпретироваться в исходной кодировке, кодировке выполнения или в другой кодировке, определяемой реализацией.
| Целочисленная арифметика в выражениях | (начиная с C99) |
Целочисленное константное выражение
Целочисленное константное выражение состоит только из
- операторов, отличных от присваивания, инкремента и декремента, вызова функции или оператора запятая, за исключением того, что операторы приведения типа могут преобразовывать арифметические типы только в целочисленные, если только они не являются частью операнда оператора sizeof , _Alignof(начиная с C11)(до C23), alignas(начиная с C23) или typeof/typeof_unqual(начиная с C23).
- целочисленных констант
- констант перечисления
- символьных констант
- констант с плавающей точкой, но только если они непосредственно используются как операнды приведения к целочисленному типу
-
операторов
sizeofс операндами, не являющимися VLA(начиная с C99)
| (начиная с C11) |
| (начиная с C23) |
Целочисленные константные выражения вычисляются во время компиляции. В следующих контекстах требуются выражения, известные как целочисленные константные выражения:
- Размер битового поля.
- Значение константы перечисления
- Метка
caseв инструкции switch - Размер массива не VLA(начиная с C99)
- Неявное преобразование целого числа в указатель.
| (начиная с C99) |
| (начиная с C11) |
| (начиная с C23) |
Статический инициализатор
Выражения, используемые в инициализаторах объектов со статической длительностью хранения или длительностью хранения thread_local storage duration либо объявленных со спецификатором класса хранения constexpr(начиная с C23), должны быть строковыми литералами или выражениями одного из следующих видов
- операторов, отличных от присваивания, инкремента и декремента, вызова функции или оператора запятая, за исключением того, что операторы приведения типа должны преобразовывать арифметические типы в другие арифметические типы, если только они не являются частью операнда оператора sizeof , _Alignof(начиная с C11)(до C23), alignof(начиная с C23) или 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:2024):
- 6.6 Константные выражения (с. 95–96)
- Стандарт 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/c/language/constant_expression