reinterpret_cast 如何处理不相关的 class?
How reinterpret_cast works when it comes to to irrelevant class?
下面代码输出的前两行是两个空行,第三、四行是两个不相等的大数,比如:
19147336
19147192
class A {
public:
A() : m_i(0) { }
protected:
int m_i;
};
class B {
public:
B() : m_d(0.0) { }
protected:
double m_d;
};
int main() {
A *pa = new A;
B *pb = new B;
std::cout << reinterpret_cast<char*>(pa) << std::endl;
std::cout << reinterpret_cast<char*>(pb) << std::endl;
std::cout << (int)reinterpret_cast<char*>(pa) << std::endl;
std::cout << (int)reinterpret_cast<char*>(pb) << std::endl;
return 0;
}
我想知道上面代码中reinterpret_cast的return到底是什么。谢谢!
您正在进行未定义的行为。编译器可以自由地生成几乎可以做任何事情的代码,包括创建一个机器人回到过去,用事后避孕药来扑灭 K&R 的 parents,以防止 C 被发明出来。
在上面的前两种情况下,您的编译器将值 0
的 int
和 double
的字节解释为 nul-terminated 字符数组, 并将其视为 0 长度缓冲区,因此不打印任何内容。
在第二组 (int)
转换案例中,它为您提供了从 new
.[=16= 获得的指针值的较低 sizeof(int)
字节的整数表示]
这些都不足为奇,但都不可靠。从严格的别名到优化,当您从事未定义的行为时,编译器可以做一些疯狂的事情,即使您没有附加时间机器或机器人,UB 的影响也会在带有 UB 的代码运行之前发生.
代码 reinterpret_cast<char*>(pa)
产生一个指向类型 A
的对象的指针。因为 A
是标准布局 class,所以以这种方式访问 A
的第一个数据成员是明确定义的。
std::cout << reinterpret_cast<char*>(pa)
。您正在调用 std::operator<<
的重载,它采用 char *
第二个参数。该函数表示输出存储在该位置的字符串。由于该位置的第一个 char
的值为 0
(因为值 0 的 int
保证由零值字节组成),这是明确定义的并且输出一个空字符串。
std::cout << reinterpret_cast<char*>(pb)
。 double
的表示是实现定义的。在常见的 IEEE754 系统上,0.0
的所有位都为零,因此您会像以前一样得到一个空白字符串。在其他系统上,这将取决于它们对数字的表示发生了什么(如果没有空字节,则可能是未定义的行为)。
std::cout << (int)reinterpret_cast<char*>(pa)
此代码将地址转换为 int
。如果地址不能表示为 int
(这可能发生在 64 位系统上),则会导致未定义的行为。否则你会得到一个代表地址的数字。
std::cout << (int)reinterpret_cast<char*>(pb)
与上例类似。
下面代码输出的前两行是两个空行,第三、四行是两个不相等的大数,比如: 19147336 19147192
class A {
public:
A() : m_i(0) { }
protected:
int m_i;
};
class B {
public:
B() : m_d(0.0) { }
protected:
double m_d;
};
int main() {
A *pa = new A;
B *pb = new B;
std::cout << reinterpret_cast<char*>(pa) << std::endl;
std::cout << reinterpret_cast<char*>(pb) << std::endl;
std::cout << (int)reinterpret_cast<char*>(pa) << std::endl;
std::cout << (int)reinterpret_cast<char*>(pb) << std::endl;
return 0;
}
我想知道上面代码中reinterpret_cast的return到底是什么。谢谢!
您正在进行未定义的行为。编译器可以自由地生成几乎可以做任何事情的代码,包括创建一个机器人回到过去,用事后避孕药来扑灭 K&R 的 parents,以防止 C 被发明出来。
在上面的前两种情况下,您的编译器将值 0
的 int
和 double
的字节解释为 nul-terminated 字符数组, 并将其视为 0 长度缓冲区,因此不打印任何内容。
在第二组 (int)
转换案例中,它为您提供了从 new
.[=16= 获得的指针值的较低 sizeof(int)
字节的整数表示]
这些都不足为奇,但都不可靠。从严格的别名到优化,当您从事未定义的行为时,编译器可以做一些疯狂的事情,即使您没有附加时间机器或机器人,UB 的影响也会在带有 UB 的代码运行之前发生.
代码 reinterpret_cast<char*>(pa)
产生一个指向类型 A
的对象的指针。因为 A
是标准布局 class,所以以这种方式访问 A
的第一个数据成员是明确定义的。
std::cout << reinterpret_cast<char*>(pa)
。您正在调用std::operator<<
的重载,它采用char *
第二个参数。该函数表示输出存储在该位置的字符串。由于该位置的第一个char
的值为0
(因为值 0 的int
保证由零值字节组成),这是明确定义的并且输出一个空字符串。std::cout << reinterpret_cast<char*>(pb)
。double
的表示是实现定义的。在常见的 IEEE754 系统上,0.0
的所有位都为零,因此您会像以前一样得到一个空白字符串。在其他系统上,这将取决于它们对数字的表示发生了什么(如果没有空字节,则可能是未定义的行为)。std::cout << (int)reinterpret_cast<char*>(pa)
此代码将地址转换为int
。如果地址不能表示为int
(这可能发生在 64 位系统上),则会导致未定义的行为。否则你会得到一个代表地址的数字。std::cout << (int)reinterpret_cast<char*>(pb)
与上例类似。