2011-11-01 75 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實際內存位置會不會在那裏你期望的那樣。您需要禁用對齊以確保不會發生。