C++20 bit_cast 对比 reinterpret_cast

C++20 bit_cast vs reinterpret_cast

根据ISO C++委员会上次会议的消息,bit-cast将在C++20标准中引入。

我知道 reinterpret_cast 由于 type aliasing rules 不适合这份工作,但我的问题是他们为什么选择不延长 reinterpret_cast 来对待 object 喜欢它的位序列表示并且更愿意将此功能作为一种新的语言结构提供?

嗯,有一个明显的原因:因为它不会做 bit_cast 所做的所有事情。即使在我们可以在编译时分配内存的 C++20 世界中,reinterpret_castconstexpr 函数中也是被禁止的。 bit_cast 的明确目标之一是能够在编译时做这些事情:

Furthermore, it is currently impossible to implement a constexpr bit-cast function, as memcpy itself isn’t constexpr. Marking the proposed function as constexpr doesn’t require or prevent memcpy from becoming constexpr, but requires compiler support. This leaves implementations free to use their own internal solution (e.g. LLVM has a bitcast opcode).

现在,您可以说您可以将 reinterpret_cast 的这种特定用法扩展到 constexpr 上下文。但这使规则变得复杂。不能简单的知道reinterpret_cast不能用在constexpr码段,还得记住reinterpret_cast不能用的具体形式

此外,还有一些实际问题。即使您想走 reinterpret_cast 路线,std::bit_cast 也是一个库函数。通过委员会获得库功能总是比语言功能更容易,即使它会获得一些编译器支持。

然后是更主观的东西。 reinterpret_cast 通常被认为是一种固有的危险操作,在某种程度上表明 "cheating" 类型系统。相比之下,bit_cast 不是。它正在生成一个新对象,就好像通过从现有对象复制其值表示一样。它是一个低级工具,但它不是一个会扰乱类型系统的工具。因此,以与拼写 "dangerous" 操作相同的方式拼写 "safe" 操作会很奇怪。

事实上,如果您确实以相同的方式拼写它们,就会开始质疑为什么这是合理定义的:

float f = 20.4f;
int i = reinterpret_cast<int>(f);

但这有点糟糕:

float f = 20.4f;
int &i = reinterpret_cast<int &>(f);

当然,语言律师或熟悉严格别名规则的人会理解为什么后者不好。但是对于外行来说,如果用reinterpret_cast做位转换没问题,不清楚为什么用reinterpret_cast转换pointers/references解释一个已有的对象是错误的作为转换类型。

不同的工具应该有不同的拼写。

编译器对 C 和 C++ 语言标准的现代、严格解释的高级语言性质与您可以使用 reinterpret_cast 将一堆字节重新解释为另一个字节的概念之间存在根本不匹配对象。请注意,在大多数情况下,所谓的 "strict aliasing" 规则甚至不能用于取消任何重新解释字节的尝试,因为代码首先不会定义行为:reinterpret_cast<float*>(&Int) 甚至不是指针对于一个浮点对象,它是一个指向恰好具有错误类型的整数的指针。您不能取消引用它,因为在那个地方没有创建浮动对象;如果有的话,它的生命周期就不会开始;如果它的生命周期已经开始,它将是未初始化的。

如果您在这里没有合适的浮点对象,恰好表示有效浮点位模式的字节就不能被解释为这样。

一个有效的非空指针不仅仅是恰好正确对齐的区域起始地址的类型化值; 一个非 null 的有效指针指向一个特定的对象(或者数组末尾的指针或一个对象的普通 "array")。

我什至没有看到 "strict aliasing" 批准的标量重新解释转换(signed/unsigned 混合)可能有效,因为该地址存在非符号(resp。无符号)整数对象(和编译器显然也不能使用无符号(resp.signed)原始值。

无论哪种方式,C++ 的设计都有问题,因为它混合了不同的语言(一些非常低级别,一些非常高级)并且严重损坏。