为什么reinterpret_cast不是 constexpr?

Why is reinterpret_cast not constexpr?

本文关键字:constexpr 不是 cast reinterpret 为什么      更新时间:2023-10-16

请考虑以下代码片段:

static constexpr uint8_t a = 0;
static constexpr const int8_t *b = reinterpret_cast<const int8_t *>(&a);

这无法用error: a reinterpret_cast is not a constant expression编译,因为C++标准禁止在constexpr中使用reinterpret_cast

但是,如果我想将值 b 存储在PROGMEM中(对于 AVR 微控制器(,编译会成功:

static constexpr uint8_t a = 0;
static const int8_t PROGMEM *const b = reinterpret_cast<const int8_t *>(&a);

在这种情况下,编译器能够证明表达式reinterpret_cast<const int8_t *>(&a)是编译时常量,因为它将其结果(指向包含零的某个字节的地址(插入到二进制文件的程序空间中:

_ZL1g:
.zero   1
.section        .progmem.data,"a",@progbits
.type   _ZL1b, @object
.size   _ZL1b, 2
_ZL1b:
.word   _ZL1g

另外,我的理解是reinterpret_cast是一个编译时指令。那么为什么不能在constexpr里面使用呢?

在运行时,C++语言具有未定义行为的概念。在某些(明确指定(条件下,程序具有未定义的行为,这意味着它可以表现出任何行为:它可以崩溃,它可以永远挂起,它可以打印乱码,它可以看起来工作,或者它可以做任何事情。为什么存在这种情况的简化解释是性能。

在运行时,这是一种权衡(如果您愿意的话,这是一种折衷(,但在编译时是不可接受的。如果标准允许在编译时使用 UB,不仅在编译程序或无限编译时崩溃是合法的,而且您永远无法确定编译的可执行文件的有效性。

因此,任何形式的constexpr都必须 100% 没有未定义的行为。没有例外。没有回旋余地。

UB的一个臭名昭著的来源是reinterpret_castreinterpret_cast的有效用途很少,大多数都会导致UB。另外,几乎不可能检查使用是否有效。因此,在编译过程中不允许reinterpret_cast,即在 constexpr 中不允许这样做。

那么为什么它不能在 constexpr 中使用呢?

仅仅因为标准不允许。 自 C++11 年以来,constexpr一直是针对不同标准不断扩展的功能,因此很自然地认为reinterpret_cast用途的子集可以工作。

问题是允许它是否真的有用或积极有害。reinterpret_cast很少有好的用途,特别是如果你在严格的混叠规则成立的情况下编程和编译你的代码:很容易创建破坏它的指针。

另一方面,很明显,对于嵌入式用户和专门的编译器/标志/环境,它在某种程度上可能是有用的。