繁体   English   中英

为什么 reinterpret_cast 不是 constexpr?

[英]Why is reinterpret_cast not constexpr?

考虑以下片段:

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_cast reinterpret_cast有效用途很少,大多数都会导致 UB。 此外,几乎不可能检查使用是否有效。 所以在编译期间不允许reinterpret_cast ,即在 constexpr 中是不允许的。

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

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

问题是允许它实际上是有用的还是有害的。 reinterpret_cast很少有好的用途,特别是如果你编程和编译你的代码时假设严格的别名规则成立:很容易创建破坏它的指针。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM