Namespaces
Variants

Constant expressions

From cppreference.net

Несколько видов выражений известны как constant expressions .

Содержание

Препроцессорное константное выражение

Выражение, следующее за #if или #elif должно раскрываться в

Символьные константы, когда вычисляются в #if -выражениях, могут интерпретироваться в исходной символьной кодировке, исполнительной символьной кодировке или в некоторой другой определяемой реализацией символьной кодировке.

Целочисленная арифметика в #if -выражениях выполняется с использованием семантики intmax_t для знаковых типов и uintmax_t для беззнаковых типов.

(since C99)

Целочисленное константное выражение

Целочисленное константное выражение — это выражение, которое состоит только из

  • _Alignof (до C23) alignas (начиная с C23) операторы
(начиная с C11)
  • именованные и составные литеральные константы, которые имеют целочисленный тип или которые имеют арифметический тип и являются непосредственными операндами приведений
(since C23)

Целочисленные константные выражения вычисляются во время компиляции. Следующие контексты требуют выражений, известных как целочисленные константные выражения :

(начиная с C99)
(начиная с C11)
  • Количество бит N для целочисленного типа с точной битовой шириной ( _BitInt ( N ) )
(начиная с C23)

Статический инициализатор

Выражения, которые используются в инициализаторах объектов со статической и thread_local продолжительностью хранения или объявленных с описателем класса хранения constexpr (since C23) должны быть либо строковыми литералами, либо выражениями, которые могут быть одним из следующих

1) арифметическое константное выражение , которое является выражением любого арифметического типа, состоящим из
(since C11)
  • именованных или составных литеральных констант арифметического типа
(since C23)
2) нулевая константа указателя (например, NULL ).
3) address constant expression , который является
  • нулевым указателем
  • lvalue , обозначающим объект со статической storage duration , или обозначением функции, преобразованным в указатель либо
  • с использованием унарного оператора взятия адреса
  • приведением целочисленной константы к указателю
  • неявным conversion массива к указателю или функции к указателю.
4) address constant expression некоторого полного типа объекта, плюс или минус integer constant expression .
5) именованная константа , то есть идентификатор, который является
  • константой перечисления
  • предопределённой константой (одной из true , false или nullptr )
  • объявлен с спецификатором класса хранения constexpr и имеет объектный тип
или постфиксное выражение, применяющее оператор доступа к члену . к именованной константе структурного или объединённого типа, даже рекурсивно.
6) константа составного литерала , которая является
  • составным литералом с спецификатором класса хранения constexpr
  • постфиксным выражением, применяющим оператор доступа к члену . к константе составного литерала структурного или объединённого типа, даже рекурсивно.

Константа структуры или объединения - это соответственно именованная константа или константа составного литерала с типом структуры или объединения. Если оператор доступа к члену . обращается к члену константы объединения, доступный член должен совпадать с членом, который инициализируется инициализатором константы объединения.

(since C23)
7) константное выражение одной из других форм, принимаемых реализацией.

В отличие от целочисленных константных выражений, статические инициализирующие выражения не обязаны вычисляться на этапе компиляции; компилятор имеет право преобразовать такие инициализаторы в исполняемый код, который вызывается до запуска программы.

static int i = 2 || 1 / 0; // инициализирует i значением 1

Значение статического инициализатора с плавающей точкой никогда не бывает менее точным, чем значение того же выражения, выполняемого во время выполнения, но может быть более точным.

Выражения с плавающей точкой констант

Арифметические константные выражения типов с плавающей точкой, которые не используются в статических инициализаторах, всегда вычисляются как-будто во время выполнения и подвержены влиянию текущего округления (если FENV_ACCESS включен) и сообщают об ошибках в соответствии с math_errhandling .

void f(void)
{
#pragma STDC FENV_ACCESS ON
    static float x = 0.0 / 0.0; // статический инициализатор: не вызывает исключение
    float w[] = { 0.0 / 0.0 };  // вызывает исключение
    float y = 0.0 / 0.0;        // вызывает исключение
    double z = 0.0 / 0.0;       // вызывает исключение
}

Примечания

Если выражение вычисляется в значение, которое не может быть представлено его типом, оно не может использоваться как константное выражение.

Реализации могут принимать другие формы константных выражений. Однако эти константные выражения не считаются целочисленными константными выражениями, арифметическими константными выражениями или адресными константными выражениями и, следовательно, не могут использоваться в контекстах, требующих этих видов константных выражений. Например, 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 CONSTANT EXPRESSIONS

Смотрите также

Документация C++ для Константных выражений