2012-12-04 36 views
4

我正在第一次使用結構指針,我似乎無法理解這裏發生了什麼。我的測試應用了xor的基本屬性,它表示x^y^y = x,但不包含在C中?我無法理解結構指針的這種行爲和XOR

下面的代碼在我的主程序中,準確地恢復所有「測試」的字母(我繼續在屏幕上打印,但我省略了很多垃圾,以便將此問題縮短ER))。該結構「AES」是指這樣的定義:

typedef uint32_t word; 

struct aes { 

word iv[4]; 
word key[8]; 
word state[4]; 
word schedule[56]; 

}; 

根據上下文可能暗示,封裝項目是AES實現(我想通過嘗試新的技術,以加快我目前的一個)。

在我的測試,make_string和make_state可靠地工作,即使在功能有問題,但對於引用的緣故:

void make_string (word in[], char out[]) { 

for (int i = 0; i < 4; i++) { 

    out[(i * 4) + 0] = (char) (in[i] >> 24); 
    out[(i * 4) + 1] = (char) (in[i] >> 16); 
    out[(i * 4) + 2] = (char) (in[i] >> 8); 
    out[(i * 4) + 3] = (char) (in[i]  ); 

} 

} 

void make_state(word out[], char in[]) { 

for (int i = 0; i < 4; i++) { 

    out[i] = (word) (in[(i * 4) + 0] << 24)^
       (word) (in[(i * 4) + 1] << 16)^
       (word) (in[(i * 4) + 2] << 8)^
       (word) (in[(i * 4) + 3]  ); 

} 

} 

不管怎麼說,這是不工作的模塊。正是這種功能,我試圖通過收納它拿走的功能模塊化:

char test[16] = { 
    'a', 'b', 'c', 'd', 
    'e', 'f', 'g', 'h', 
    'i', 'j', 'k', 'l', 
    'm', 'n', 'o', 'p' 
}; 

aes cipher; 

struct aes * work; 

work = &cipher; 

make_state(work->state, test); 

work->state[0] ^= 0xbc6378cd; 
work->state[0] ^= 0xbc6378cd; 

make_string(work->state, test); 

儘管此代碼的工作,通過它傳遞給函數做同樣的事情不會:

void encipher_block (struct aes * work, char in[]) { 

    make_state(work->state, in); 

    work->state[0] ^= 0xff00cd00; 

    make_string(work->state, in); 

} 

void decipher_block (struct aes * work, char in[]) { 

    make_state(work->state, in); 

    work->state[0] ^= 0xff00cd00; 

    make_string(work->state, in); 

} 

但是,通過在加密和解密中刪除make_state和make_string調用,它可以按預期工作!

make_state(work->state, test); 

encipher_block(&cipher, test); 
decipher_block(&cipher, test); 

make_string(work->state, test); 

所以澄清,我沒有問題!我只是想了解這種行爲。

回答

2

變化charunsigned charchar可能會被簽名,並且可能位於您的系統上,這會在轉換爲其他整數類型和轉換時導致問題。

在表達式(char) (in[i] >> 24) in make_string中,將一個無符號的32位整數轉換爲有符號的8位整數(在您的C實現中)。該表達式可以將值轉換爲在char中不可表示的char,值尤其是從128到255的值。根據C 2011 6.3.1.3 3,結果是實現定義的或者實現定義的信號被引發。

在表達式(word) (in[(i * 4) + 3] )make_statein[…]char,這是一個符號的8位整數(在C實現)。根據C 2011 6.3.1.1中定義的常規整數促銷,此char轉換爲int 2.如果char爲負數,則生成的int爲負數。然後,當它轉換爲無符號的word時,效果是符號位被複製爲高24位。例如,如果char的值爲-166(0x90),則結果將爲0xffffff90,但您需要0x00000090

更改charunsigned char貫穿此代碼。

此外,在make_state,in[(i * 4) + 0]應轉換爲word左轉之前。這是因爲它將以unsigned char開頭,在轉變之前將其升級爲int。如果它具有某些高位設置的值,例如0x80,則將其左移24位會生成一個值,該值不能在int中表示,如0x80000000。根據C 2011 6.5.7 4,行爲是未定義的。

在大多數C實現中這不會成爲問題;二進制補碼通常用於有符號整數,並且結果將根據需要進行換行。另外,我認爲這是編譯器開發人員設計的模型情況,因爲它是一個非常常見的代碼結構。但是,爲了提高便攜性,鑄造到word將避免溢出的可能性。

+0

對於按位運算,我認爲這並不重要。 –

+0

我在答案中添加了文字,解釋'char'如何破壞你的代碼。 –

+0

啊,謝謝。我從來不會猜到它是這樣做的。 –

0

make_state()函數會覆蓋在第一個參數中傳遞的數組。如果你把encipher_block()decipher_block()機構行內,你會得到這樣的:

/* encipher_block inline */ 
make_state(work->state, in); 
work->state[0] ^= 0xff00cd00; 
make_string(work->state, in); 

/* decipher_block inline */ 
make_state(work->state, in); /* <-- Here's the problem */ 
work->state[0] ^= 0xff00cd00; 
make_string(work->state, in); 
+0

該代碼旨在改變其第一個參數。該模型是'make_state'將數據放入工作表單中,'make_string'將其返回到字符串形式。這種轉變應該僅僅改變數據的安排,而不是其價值。這個概念是工作形式中的兩個相同值的XOR應導致身份操作(無變化)。他們不。原因不是寫作工作 - >狀態,這是有效的暫存空間。原因是'char'的不良簽名。 –