常量表达式
几种不同类型的表达式被称为 常量表达式
目录 |
[编辑] 预处理器常量表达式
紧跟在 #if
或 #elif
之后的表达式必须展开为
字符常量在 #if
表达式中求值时,可以根据源字符集、执行字符集或其他实现定义的字符集进行解释。
|
(C99 起) |
[编辑] 整型常量表达式
整型常量表达式是由以下内容组成的表达式:
- 运算符,除了 赋值、自增、自减、函数调用或 逗号运算符,但 类型转换 运算符只能将算术类型转换为整型,除非它们是 sizeof 、_Alignof(C11 起)(C23 前)、alignas(C23 起) 或 typeof/typeof_unqual(C23 起) 运算符的操作数。
- 整型常量
- 枚举常量
- 字符常量
- 浮点常量,但仅当它们立即用作转换为整型的类型转换运算符的操作数时
-
sizeof
运算符 ,其操作数不是 VLA(C99 起)
|
(C11 起) |
|
(C23 起) |
整型常量表达式在编译时求值。以下上下文需要被称为 整型常量表达式 的表达式:
- 位域的大小。
- 枚举常量的值
- switch 语句的
case
标签 - 非 VLA 数组的大小
- 整型到指针的隐式 转换。
|
(C99 起) |
|
(C11 起) |
|
(C23 起) |
[编辑] 静态初始化器
用于具有静态和 thread_local 存储期限 的对象 或用 constexpr 存储类说明符声明的对象(C23 起) 的初始化器中的表达式,必须是字符串字面量或可以是以下之一的表达式
(C11 起) |
|
(C23 起) |
NULL
)
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 常量表达式 (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++ 文档,关于 常量表达式
|