C++工会内部
C++ Unions Internals
我正在尝试学习C++,并在国际象棋程序中遇到了一些我需要帮助理解的代码。我有一个工会,例如:
union b_union {
Bitboard b;
struct {
#if defined (BIGENDIAN)
uint32_t h;
uint32_t l;
#else
uint32_t l;
uint32_t h;
#endif
} dw;
};
上面的代码属于 else 条件。
位板定义为uint64_t。如果我有一个值,比如说0x0025f780,即282578800148862,并且我设置了union.b = 0x0025f780,那么union.dw.l更新为16843134,union.dw.h更新为65793。在本质上,l 和 h 以 3435973836 开头。在内部,发生了什么?我对C++相当陌生。只是想让我了解工会在内部的工作方式。
非常感谢您的任何见解。
大卫
联合意味着组件将占用相同的内存位置。在您演示的代码示例中,目的是允许您直接引用b
的上限和下部 32 位。
请注意,此代码调用未定义(或实现定义(的行为。这是因为您正在从写入数据的其他元素访问联合元素。
因此,b
是一个 64 位整数,将与 l
和 h
共享相同的内存位置,后者指的是下部和上部 32 位。当然,它的有效性取决于机器的字节序 - 这就是为什么有预处理器if-else的原因。
编辑:您的特定示例也不正确。但这里有一个固定版本:
设置 b = 282578800148862
时,(b = 0x101010101017e)
。上部和下部 32 位为:
00010101 0101017e
所以
l = 0x0101017e = 16843134
h = 0x00010101 = 65793
基本上,联合允许您描述单个内存块的几种使用方式。正常情况是在同一位置存储两个不相关的值,只要一次只使用一个值,它们就可以工作。(写入一个变体会破坏另一个变体。
联合的另一个非常常见的用途是访问另一个元素的一部分(顺便说一下,这是未定义的行为(。在您的情况下,64 位整数的两个视图。一个是整个整数,另一个是两半,作为单独的 32 位实体。
请注意,不同的计算机存储 64 位值的方式不同。有些存储从高值到低值的字节(大端序(,有些则相反(小字节序(,有些使用混合形式(混合字节序(。顺便说一下,这些名字来自《格列佛游记》,有些人从大边吃鸡蛋,有些人从尖头吃鸡蛋。
在您的情况下,我建议您一起放弃联合并使用以下命令访问零件:
low = uint32_t(b);
high = uint32_t(b >> 32);
以上将适用于所有架构,并且与联合一样快,甚至更快。
联合一次只声明一个值。它可以"声明"多个值,但一次只能保留一个值,并且前一个值会被覆盖。在您的情况下,union.b 设置了值,但将其分配给了其他变量。你不能保存 BitBoard 值和结构值,它必须是其中之一。所以当你回去检查时,你已经覆盖了你的旧值。我认为结构更适合这种情况,但如果您不确定,您可以随时尝试单步执行代码。在这里,您的 l 和 h 值开始与导致问题的位板合并。
您最好处理十六进制数。
发生的情况是union dw
和uint64_t b
占用内存中的相同空间。l
和h
表示b
的低位和高位32位部分。
在大端序中,当值在内存中时,高 32 位部分也是较高的位。在小端序中,情况恰恰相反。这就是为什么你在那里有#ifdef
。
这使得l
低32位b
(0xf780(和h
- 高32位b
(0x0025(。
您提到的实际值没有多大意义,您可能还有其他问题。 282578800148862不是0x0025f780。
您必须小心联合,因为基础数据表示形式可能不同。例如,您的struct
可能对齐,因此l
和h
的实际内存位置不会在您期望的位置。您需要禁用对齐以确保它不会发生。
- 将函数类成员映射到类本身内部
- Boost Spirit,获取迭代器内部语义动作
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 内联函数中具有内部链接的全局变量
- 在函数内部的声明中初始化数组,并在外部使用它
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 卷曲bracers内部结构的声明
- 从函数角度看ID到文件路径的内部与外部映射
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- 如何在pugixml中获取节点的内部XML
- 使用C链接在函数内部创建C++模板
- 指针没有更新它在void函数内部指向的值
- 方法内部但循环仍得到预期的不合格id错误C++
- C++:具有内部链接的正向声明常量
- SDL_PollEvent() 无法捕获类函数内部SDL_QUIT?
- libcurl 和 DNS ttl 中的内部连接管理
- 如何修改 lambda 内部字符串的向量
- 如果我将嵌套映射作为多重映射的值,如何将值插入内部映射?
- 来自 Android 应用程序内部的 boost 类型的 boost::wrapexcept<boost::system::system_error> 的未捕获异常
- 类内部和外部静态 constexpr 元组之间的差异