《The C++ Programming Language》中union避免类型转换的原理问询
嘿,这个问题问得好!我来帮你拆解一下Stroustrup在《The C++ Programming Language》里提到的这个union用法,到底是怎么做到“避免类型转换”的。
首先,先还原书中提到的Fudge union的典型写法,大概是这样的:
union Fudge { void* p; // 指针类型成员 long i; // 整数类型成员 };
为什么用Union能避免类型转换?
要理解这点,我们先对比不用union的写法:如果想获取空指针(指针0)的内存表示,你通常需要用显式的类型转换,比如:
// 用reinterpret_cast做显式类型转换 long null_ptr_representation = reinterpret_cast<long>(nullptr);
这里的reinterpret_cast就是典型的类型转换操作,它明确告诉编译器“我要把一个指针类型转换成整数类型”。
而用Fudge union的话,写法是这样的:
Fudge f; f.p = nullptr; // 给指针成员赋值为空指针(即指针0) long null_ptr_representation = f.i; // 直接读取整数成员的值
你看,这里完全没有用到任何类型转换操作符(比如reinterpret_cast、C风格的(long)强制转换),只是通过union的成员访问,直接从同一块内存里读出了另一种类型的值。
核心原理:Union的内存共享特性
Union的本质是所有成员共享同一块内存空间——也就是说,f.p和f.i占用的是内存中完全相同的字节。当你给f.p赋值为nullptr时,内存里会写入空指针对应的字节序列;之后读取f.i,就是把这些字节序列直接解释成long类型的值。
这种方式相当于“绕过”了显式类型转换的语法,让你在不同类型之间访问同一块内存,而不需要写转换操作符——这就是Stroustrup说的“刻意使用union来避免类型转换”的核心意思。
补充:C++标准里的注意事项
虽然这种union类型双关的用法在C里很普遍,在C里也被很多编译器支持,但严格来说,C标准对这种“写一个成员读另一个成员”的行为有一定限制(仅对某些POD类型或布局兼容类型是合法的)。不过对于指针和整数这种常见场景,主流编译器(GCC、Clang、MSVC)都允许这种用法,这也是Stroustrup会把它作为例子的原因。
内容的提问来源于stack exchange,提问作者Birbal

