C23标准中constexpr支持哪些新类型与操作?有何限制?
C23中constexpr支持的新类型、操作及限制
C23引入constexpr关键字,用于定义编译时常量,可替代传统枚举或宏来实现类型安全的编译期常量定义,示例如下:
constexpr int x = 10; constexpr int y = x + 10; // 合法 switch (some_var) { case y: // 合法,y是编译时常量 // ... } static int z = y; // 合法
相较于C标准此前仅支持整数常量、全局/static对象地址作为编译时常量,且仅能执行有限算术运算的限制,C23对constexpr的能力做了大幅扩展,具体如下:
支持的新类型与操作
新增支持的类型
- 浮点类型:
float、double、long double均可定义为constexpr对象,编译时即可完成浮点运算,例如:constexpr double pi = 3.1415926; constexpr double circle_area = pi * 5 * 5; // 编译时计算圆面积 - 指针与数组:支持编译时指针算术、空指针比较,以及
constexpr数组的元素访问、长度计算;还能在编译时初始化数组,例如:constexpr int arr[] = {1,2,3,4}; constexpr int arr_len = sizeof(arr)/sizeof(arr[0]); // 编译时获取数组长度 constexpr int* ptr = &arr[2]; // 编译时获取数组元素地址 - 结构体/联合体:支持编译时初始化结构体,以及访问其成员(只要成员类型支持
constexpr),例如:typedef struct { int x; double y; } Point; constexpr Point p = {10, 20.5}; constexpr int px = p.x; // 编译时访问结构体成员
新增支持的操作
- 编译时浮点算术运算:加减乘除、取模、幂运算等,只要运算结果无未定义行为
- 编译时位运算:移位、与、或、非、异或等操作,扩展到更多支持的类型
- 编译时安全类型转换:整数与浮点数之间的constexpr转换(无溢出等未定义行为时)
- 调用自定义constexpr函数:只要函数内部操作均符合constexpr规则,即可在编译时执行
- 结合
if constexpr实现编译时分支逻辑:根据constexpr表达式的结果选择编译代码路径 - 基于
sizeof、alignof的复杂编译时计算:可将这些运算符的结果参与更复杂的constexpr表达式
核心限制
- 所有constexpr表达式必须是编译时可确定的,不能依赖运行时变量(如用户输入、栈上非static变量)
- 禁止出现未定义行为:比如除以零、数组越界、浮点溢出、访问局部非static对象的地址等
- 指针类型的constexpr操作仅允许使用全局对象、static对象、字符串字面量的地址,不能获取局部非static对象的地址
- 浮点类型的constexpr运算可能存在编译器实现差异:不同编译器的浮点精度处理可能导致结果略有不同
- constexpr函数内不能包含
goto、try-catch,也不能调用非constexpr函数 - 联合体的constexpr操作仅能访问当前活跃的成员,否则属于未定义行为
内容的提问来源于stack exchange,提问作者CPlus
相关产品推荐
相关产品推荐

