Con*_*lor 9 c++ avr reinterpret-cast constexpr c++11
考虑以下片段:
static constexpr uint8_t a = 0;
static constexpr const int8_t *b = reinterpret_cast<const int8_t *>(&a);
Run Code Online (Sandbox Code Playgroud)
这无法通过 编译error: a reinterpret_cast is not a constant expression,因为C++ 标准禁止使用reinterpret_castin constexpr。
但是,如果我想将值 b 存储在PROGMEM(对于 AVR 微控制器)中,编译会成功:
static constexpr uint8_t a = 0;
static const int8_t PROGMEM *const b = reinterpret_cast<const int8_t *>(&a);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器能够证明该表达式reinterpret_cast<const int8_t *>(&a)是编译时常量,因为它将其结果(指向某个包含零的字节的地址)插入到二进制程序空间中:
_ZL1g:
.zero 1
.section .progmem.data,"a",@progbits
.type _ZL1b, @object
.size _ZL1b, 2
_ZL1b:
.word _ZL1g
Run Code Online (Sandbox Code Playgroud)
另外,我的理解是这reinterpret_cast是一个编译时指令。那么为什么它不能在 a 中使用constexpr?
在运行时,C++ 语言具有未定义行为的概念。在某些(明确指定的)条件下,程序具有未定义的行为,这意味着它可以表现出任何行为:它可以崩溃,它可以永远挂起,它可以打印胡言乱语,它可以看起来工作,或者它可以做任何事情。为什么会出现这种情况的一个简单解释是性能。
在运行时,这是一种折衷(如果您愿意,可以进行折衷),但在编译时这是不可接受的。如果标准允许在编译时使用 UB,不仅在编译程序或无限编译时发生崩溃是合法的,而且您永远无法确定编译后的可执行文件的有效性。
因此,任何形式的constexpr都必须 100% 没有未定义的行为。没有例外。没有余地。
UB 的一个臭名昭著的来源是reinterpret_cast. 的有效用途很少reinterpret_cast,大多数会导致 UB。此外,几乎不可能检查使用是否有效。所以reinterpret_cast在编译期间是不允许的,即在 constexpr 中是不允许的。