2011-11-01 71 views
1

我正在尝试学习Eabout C++,并在国际象棋程序中遇到一些我需要帮助理解的代码。我有一个工会,如: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条件。

Bitboard定义为uint64_t。如果我有一个值,比如说0x0025f780,它是282578800148862,并且我设置union.b = 0x0025f780,那么union.dw.l更新为16843134,union.dw.h更新为65793.从头开始,l和h从在内部,发生了什么事?我对C++相当陌生。试图把我的头围绕着工会在内部工作。

非常感谢任何见解。

大卫

回答

1

基本上,联盟可以让你介绍几种方法被用于单件的记忆。正常情况下,将两个不相关的值存储在同一位置,只要您在当时只使用一个值即可。 (写入一个变体会破坏另一个变体。)

联合的另一个非常常见的用途是访问另一个元素的部分(顺便说一下,这是未定义的行为)。在你的情况下,一个64位整数的两个视图。一个是整数,另一个是两个半部分,作为单独的32位实体。

需要注意的是不同的计算机上存储一个64位的值不同。有些存储从更高价值到更低价值(大端)的字节,一些反过来(小端),有些使用混合形式(混合端序)。顺便说一下,这些名字来自格列佛游记,有些人从大方吃了蛋,有些人从尖角吃了蛋。

在你的情况,我建议你放弃工会一起,使用访问部分:

low = uint32_t(b); 
high = uint32_t(b >> 32); 

以上将在所有的架构工作,是为快,甚至更快,使工会。

+0

甜。我实际上已经想出了如何通过>> 32得到“高”,但不知道“l”部分。你为我节省了很多时间。非常感谢。 –

+0

我一直想知道为什么它是“e”的“endian”。 –

5

联合意味着组件将占用相同的内存位置。在你已经显示的代码示例中,目的是让你直接引用b的高32位和低32位。

请注意,此代码调用未定义(或实现定义)的行为。这是因为您正在从写入数据的其他元素访问联合元素。

b所以这是一个64位整数,将共享相同的存储单元lh其是指下部和上部32位。当然,这个的有效性取决于机器的endian - 这就是为什么预处理器if-else的原因。

编辑:你特别的例子也是不正确的。但这里有一个固定版本:

当您设置b = 282578800148862,(b = 0x101010101017e)。上部和下部32位是:

00010101 0101017e 

所以

l = 0x0101017e = 16843134 
h = 0x00010101 = 65793 
+0

哼,我真的不知道l和h代表什么。谢谢你指出。我会多玩一点。这是国际象棋代码,我花了一个星期左右的时间试图加速使用魔术棋盘。相当复杂的东西。 –

1

工会与在一个时间只有一个值声明。它可以“声明”多个值,但每次只保留一个值,而前一个值被覆盖。在你的情况,union.b设置值,但分配给其他变量。您不能保存BitBoard值和结构值,它需要是一个或另一个。所以当你去检查时,你已经覆盖了你的旧价值观。我认为在这种情况下结构更适合,但如果您不确定,则可以尝试单步执行代码。在这里,你的l和h值开始与导致问题的棋盘合并。

0

你最好在这种情况下处理十六进制数。

会发生什么情况是union dwuint64_t b在内存中占用相同的空间。 lh分别表示b的低位和高位32位部分。

big-endian中,当值在存储器中时,高32位部分也是较高位。在小尾巴中恰恰相反。这就是为什么你在那里有#ifdef

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

你提到的没有多大意义的实际值,你可能有一些其他的问题存在。 282578800148862是不是 0x0025f780。

你必须要小心,因为工会的底层数据表示可能会有所不同。例如,您struct可能会被排列,因而的lh实际内存位置会不会在那里你期望的那样。您需要禁用对齐以确保不会发生。