为何constexpr中超出作用域变量的地址等于零?
constexpr函数中栈变量地址编译期求值的特殊处理
为什么这段代码能编译通过?
C++20扩展了constexpr函数的能力,允许在constexpr函数内获取自动变量(栈变量)的地址,但有个关键前提:只要不对这个地址进行解引用操作,编译期求值就是合法的。
你的代码里:
constexpr auto foo() { int x = 5; return &x; } static_assert(foo() == 0);
当foo()在编译期上下文(比如static_assert)中被调用时,编译器不会为x分配实际的栈内存。此时返回的地址是一个编译期占位值,GCC选择用0来表示这个无实际意义的地址——这完全符合C++标准的规则,标准允许编译器将这类未绑定到实际存储的指针映射为任意值,只要程序没有通过该指针访问内存。
必须注意的风险
如果尝试在运行期调用foo()并解引用返回的指针,会触发未定义行为:
int main() { int* p = foo(); *p = 10; // 严重错误:运行期x已销毁,指针悬空;编译期返回的地址也无对应内存 }
只有在constexpr函数内部、同一个求值上下文里解引用这个地址才是合法的,比如:
constexpr int bar() { int x = 5; return *&x; // 合法,编译期直接返回5 }
标准规则简述
C++20标准明确,constexpr求值过程中获取自动变量的地址是允许的,但该指针的有效范围仅限于当前constexpr求值过程内部。如果将其传出到编译期求值上下文之外,编译器可以将其视为一个“无效占位指针”,只要程序不对其进行内存访问操作,代码就是合法的。
内容的提问来源于stack exchange,提问作者Boris
相关产品推荐
相关产品推荐

