命名空间
变体
操作

常量表达式

来自 cppreference.com
< c‎ | 语言

几种类型的表达式被称为常量表达式

内容

[编辑] 预处理器常量表达式

#if#elif之后,表达式必须扩展为

#if表达式中求值时,字符常量可能会在源字符集、执行字符集或其他一些实现定义的字符集中进行解释。

#if表达式中执行整数运算时,将使用intmax_t的语义来处理有符号类型,而使用uintmax_t来处理无符号类型。

(自C99起)

[编辑] 整数常量表达式

整数常量表达式是一个仅包含以下内容的表达式:

(自C11起)
  • 命名和复合字面量常量,它们是整数类型,或者它们是算术类型并且是强制转换的直接操作数
(自C23起)

整数常量表达式在编译时求值。以下上下文需要被称为整数常量表达式的表达式

(自C99起)
(自C11起)
  • 位精确整数类型的位数 N (_BitInt(N))
(自C23起)

[编辑] 静态初始化器

在具有静态和线程本地存储持续时间 或使用constexpr存储类说明符声明(自C23起)的对象的初始化器中使用的表达式必须是字符串字面量,或者可以是以下之一的表达式:

1) 算术常量表达式,它是一个任何算术类型的表达式,包含:
(自C11起)
  • 算术类型的命名或复合字面量常量
(自C23起)
2) 空指针常量(例如 NULL
3) 地址常量表达式,它是:
  • 使用一元取地址运算符
  • 将整数常量强制转换为指针
  • 使用数组到指针或函数到指针的隐式转换
4) 某些完整对象类型的地址常量表达式,加上或减去一个整数常量表达式
5) 命名常量,即:
  • 枚举常量
  • 预定义常量(truefalsenullptr之一)
  • 使用存储类说明符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 常量表达式 (p: TBD)
  • C17标准 (ISO/IEC 9899:2018)
  • 6.6 常量表达式 (p: 76-77)
  • C11标准 (ISO/IEC 9899:2011)
  • 6.6 常量表达式 (p: 106-107)
  • C99标准 (ISO/IEC 9899:1999)
  • 6.6 常量表达式 (p: 95-96)
  • C89/C90标准 (ISO/IEC 9899:1990)
  • 3.4 常量表达式

[编辑] 参见

C++ 文档 for 常量表达式