c++ reinterpret_cast〈const unsigned char*>的语义

p8ekf7hl  于 2023-02-10  发布在  其他
关注(0)|答案(4)|浏览(253)

我偶然沿着下面的代码:

#include <bitset>
#include <iostream>

int main() {
  int x = 8;
  void *w = &x;
  bool val = *reinterpret_cast<const unsigned char*>(&x);
  bool *z = static_cast<bool *>(w);
  std::cout << "z (" << z << ") is " << *z << ": " << std::bitset<8>(*z) << "\n";
  std::cout << "val is " << val << ": " << std::bitset<8>(val) << "\n";
}

使用-O3时,这将生成输出:

z (0x7ffcaef0dba4) is 8: 00001000
val is 1: 00000001

但是,如果使用-O 0,则会生成以下输出:

z (0x7ffe8c6c914c) is 0: 00000000
val is 1: 00000001

我知道解引用z会调用未定义的行为,这也是为什么我们会看到不一致的结果。但是,将reinterpret_cast解引用为val似乎不会调用未定义的行为,并且可靠地生成{0,1}值。
通过(https://godbolt.org/z/f6s11Kr96),我们看到用于x86的gcc产生:

lea     rax, [rbp-16]
        movzx   eax, BYTE PTR [rax]
        test    al, al
        setne   al
        mov     BYTE PTR [rbp-9], al

testsetne指令的作用是将非0值转换为1(并将0值保持为0)。是否有某种规则规定reinterpret_castvoid *const unsigned char *应该具有此行为?

toiithl6

toiithl61#

阅读*z的值会导致未定义的行为,这是由于严格的别名冲突(C++20 [basic.lval]/11)。表达式的类型为bool,但内存位置的对象的类型为int。只有特定的类型对允许别名,bool到int不允许。
代码的val部分不是UB,因为const unsigned char允许别名其他类型。val的初始化器将产生一个unsigned char值,其内存表示与x的第一个字节的内容相同。
然后,将该结果转换(不重新解释)为bool,如果为0则生成false,否则生成true

unhi4e5o

unhi4e5o2#

  • 访问 *(即阅读)z的值(不仅仅是解引用自身)会导致未定义的行为,因为这是一个别名冲突。(z指向int类型的对象,但访问是通过bool类型的左值进行的)

通过类型为unsigned char的左值进行的访问被明确排除在别名冲突之外。(参见[basic.lval]/11.3)
但是,从技术上讲,仍然没有规定通过unsigned char左值访问int对象的结果应该是什么,其意图是给出int对象的对象表示的第一个字节,但是目前的标准在没有规定该行为方面存在缺陷,本文P1839试图解决该缺陷。
从对象表示中阅读第一个字节作为unsigned char值后,在初始化bool val时将其隐式转换为bool。从unsigned charbool的转换是 values 的转换,不重新解释对象表示。指定零值转换为false,其他值转换为true。(参见conv.bool(https://timsong-cpp.github.io/cppwp/n4868/conv.bool))
无论您是显式地强制转换void*还是直接将int*强制转换为unsigned char*bool*,这都无关紧要。指针之间的reinterpret_cast实际上被指定为等效于static_cast<void*>,然后将static_cast指定为目标指针类型。(在您的代码中,static_castreinterpret_cast是可以互换的。)

xlpyo6sf

xlpyo6sf3#

这是未定义的行为。
根据-fsanitize=undefined

/app/example.cpp:9:41: runtime error: load of value 8, which is not a valid value for type 'bool'
/app/example.cpp:9:70: runtime error: load of value 8, which is not a valid value for type 'bool'

https://godbolt.org/z/vM5MxT4Md
特别是,-fsanitize=undefined抱怨bool应该保存truefalse,其他任何内容都是UB(我相信truefalse的位表示是由实现定义的)。

u7up0aaq

u7up0aaq4#

expr.reinterpret.cast相同
reinterpret_­cast<T>(v)
1.一个对象指针可以显式地转换成不同类型的对象指针。当对象指针类型的纯右值v转换成对象指针类型“指针指向cv T“时,结果是static_­cast<cv T*>(static_­cast<cv void*>(v))
[Note 6:将指向T1类型对象的“指向T1的指针“类型的指针转换为“指向T2的指针“类型(其中T2是对象类型,T2的对齐要求并不比T1的对齐要求更严格),并转换回其原始类型,得到原始指针值。
表达式bool val = *reinterpret_cast<const unsigned char*>(&x);是有效代码。

相关问题