C++工会内部

C++ Unions Internals

本文关键字:内部 C++      更新时间:2023-10-16

我正在尝试学习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 位整数,将与 lh共享相同的内存位置,后者指的是下部和上部 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 dwuint64_t b占用内存中的相同空间。lh表示b的低位和高位32位部分。

在大端序中,当值在内存中时,高 32 位部分也是较高的位。在小端序中,情况恰恰相反。这就是为什么你在那里有#ifdef

这使得l低32位b(0xf780(和h - 高32位b(0x0025(。

您提到的实际值没有多大意义,您可能还有其他问题。 282578800148862不是0x0025f780。

您必须小心联合,因为基础数据表示形式可能不同。例如,您的struct可能对齐,因此lh的实际内存位置不会在您期望的位置。您需要禁用对齐以确保它不会发生。