Spec-Zone.ru › C

Константные выражения

Известно несколько разновидностей выражений, называемых константными выражениями

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

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

  • операторов, отличных от присваивания, инкремента и декремента, вызова функции или оператора запятая, аргументами которых являются константные выражения препроцессора
  • целочисленных констант
  • символьных констант
  • специального оператора препроцессора defined

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

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

(начиная с C99)

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

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

  • операторов, отличных от присваивания, инкремента и декремента, вызова функции или оператора запятая, за исключением того, что операторы приведения типа могут преобразовывать арифметические типы только в целочисленные, если только они не являются частью операнда оператора sizeof , _Alignof(начиная с C11)(до C23), alignas(начиная с C23) или typeof/typeof_unqual(начиная с C23).
  • целочисленных констант
  • констант перечисления
  • символьных констант
  • констант с плавающей точкой, но только если они непосредственно используются как операнды приведения к целочисленному типу
  • операторов sizeof с операндами, не являющимися VLA(начиная с C99)
  • операторов _Alignof(до C23)alignof(начиная с C23)
(начиная с C11)
  • именованных констант и константных составных литералов целочисленного типа либо арифметического типа, являющихся непосредственными операндами операторов приведения
(начиная с C23)

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

  • Размер битового поля.
  • Значение константы перечисления
  • Метка case в инструкции switch
  • Размер массива не VLA(начиная с C99)
  • Неявное преобразование целого числа в указатель.
  • Индекс в дизайнаторе массива
(начиная с C99)
  • Первый аргумент _Static_assert
  • Целочисленный аргумент _Alignof(до C23)alignof(начиная с C23)
(начиная с C11)
  • Количество бит N целочисленного типа с точной разрядностью (_BitInt(N))
(начиная с C23)

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

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

1) арифметическое константное выражение — выражение любого арифметического типа, состоящее из
  • операторов, отличных от присваивания, инкремента и декремента, вызова функции или оператора запятая, за исключением того, что операторы приведения типа должны преобразовывать арифметические типы в другие арифметические типы, если только они не являются частью операнда оператора sizeof , _Alignof(начиная с C11)(до C23), alignof(начиная с C23) или typeof/typeof_unqual(начиная с C23)
  • целочисленных констант
  • констант с плавающей точкой
  • констант перечисления
  • символьных констант
  • операторов sizeof с операндами, не являющимися VLA(начиная с C99)
  • операторов _Alignof(до C23)alignof(начиная с C23)
(начиная с C11)
  • именованных констант или константных составных литералов арифметического типа
(начиная с C23)
2) нулевая константа указателя (например, NULL)
3) константное выражение адреса, которым является
  • нулевой указатель
  • lvalue, обозначающее объект со статической длительностью хранения, или обозначение функции, преобразованное в указатель одним из следующих способов:
    • с помощью унарного оператора взятия адреса
    • с помощью приведения целочисленной константы к указателю
    • с помощью неявного преобразования массива в указатель или функции в указатель
4) константное выражение адреса некоторого полного типа объекта плюс или минус целочисленное константное выражение
5) именованная константа, то есть идентификатор, который является
  • константой перечисления
  • предопределённой константой (одной из true, false или nullptr)
  • объявлен со спецификатором класса хранения constexpr и имеет тип объекта
либо постфиксное выражение, применяющее оператор доступа к члену . к именованной константе структурного типа или типа объединения, в том числе рекурсивно. 6) константный составной литерал, которым является
  • составной литерал со спецификатором класса хранения constexpr
  • постфиксное выражение, применяющее оператор доступа к члену . к константному составному литералу структурного типа или типа объединения, в том числе рекурсивно.

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

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

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

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

Spec-Zone.ru

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