2

我想測試,如果它是確定訪問在C結構的未對齊的成員,請參閱該代碼訪問未對齊的結構構件

#include <stdio.h> 

#pragma pack(1) /* force 1 byte alignment */ 

/* either member b or member d is mis-aligned */ 
typedef struct 
{ 
    int b; 
    unsigned char c; 
    unsigned int d; 
}A ; 


int main(int argc, char *argv[]) 
{ 
    A _a = {0}; 
    unsigned int *p = NULL; 
    unsigned int *q = NULL; 


    printf("addr of _a : 0x%08x, size of _a : %u\n", &_a, sizeof(_a)); 

    p = (unsigned int*)(&_a.b); 
    q = (unsigned int*)(&_a.d); 

    /* should this fail ? */ 
    (*p)++ , (*q)++; 

    return 0; 

} 

認爲程序會崩潰因但是事實證明它工作得很好,已經在Linux 3.6.11(GCC 4.7.2),WinXP(MingW),鍵盤在線編譯器(http://codepad.org/yOoc8ACG

解釋結果,我想操作系統已經做了一些事情來保存程序,仍然懷疑它是否適用於VxWorks或其他操作系統

注意:代碼在基於Intel的機器上運行!

在此先感謝!

+0

如果你嘗試並將p和q傳遞給另一個函數後會發生什麼?或者也許嘗試訪問這些位置的內存? – 2013-03-13 15:09:22

+1

可能重複[未對齊的內存訪問總是會導致總線錯誤?](http://stackoverflow.com/questions/1496848/does-unaligned-memory-access-always-cause-bus-errors) – ecatmur 2013-03-13 15:10:05

+0

在SPARC上運行。 – WhozCraig 2013-03-13 15:13:19

回答

1

想必您是在英特爾機器上運行。 x86架構可以處理未對齊的訪問,而不會有任何問題。不過,您可能在其他體系結構上遇到問題。即使架構碰巧不支持未對齊的訪問,但您有時可以通過在某種CPU異常處理程序中使用單字節訪問來模擬未對齊的訪問,有時操作系統可以爲您解決此問題。

我想你也想在測試程序中使用(*p)++(*q)++

+0

是的,你是對的,我應該改爲(* p)++和(* q)++ – Tracy 2013-03-13 15:19:12

0

基於x86的體系結構並不常見,因爲它們的字訪問指令可用於錯誤對齊的地址。由此產生的操作速度較慢並且不是原子的,但它起作用。

只要您的程序包含#pragma它的含義就(最好)實現定義。一般來說,將數據成員的地址分配給變量unsigned int*將使實現「忘記」它可能會錯誤對齊,因此它不會爲未對齊的加載發出代碼。因此,在其重要的體系結構中,*p*q(或兩者)都不起作用。

0

結果取決於體系結構和內核配置。通常在x86上,您可以訪問未對齊的數據,但會有一些性能損失。這主要是由於與舊系列CPU兼容。

在ARM和SPARC上,行爲取決於內核配置。這種未對齊的數據訪問可能被操作系統禁止,允許甚至模擬。在後一種情況下,硬件異常會被內核攔截,並在某些操作系統的和平代碼中被模擬。

隨着編譯器版本到位,這變得更加困難。例如,現代GCC生成一個特殊的代碼,如果它發現數據沒有對齊,就可以以非原子方式訪問未對齊的數據(即有幾條指令)。

1

上面的一些答案說「因爲它是x86,它不會失敗」,這是不完全正確的。雖然我知道沒有操作系統這樣做,但可以配置x86處理器在用戶模式下進行非對齊訪問時發生故障[不是在內核模式下,但發佈的代碼看起來像用戶模式代碼]。但正如我所說的,我知道沒有一個操作系統實際上配置了這個位,並且很可能會破壞一些代碼,而這些代碼並不期望處理器因未對齊的內存訪問而出現故障。

無論您如何查看它,未對齊訪問的行爲都是未定義的,或者最多隻能定義實現。這意味着這樣一個操作的結果範圍從「它的工作方式就像你期望的那樣」到了「程序崩潰」的一端。在這個範圍的中間可能是「它不會崩潰,但它也沒有像你期望的那麼完美」的更糟糕的選擇 - 例如,你可能會發現你剛剛獲得了對應地址的值[較低的內存地址]您希望獲取的數據,或者獲取確實執行正確,但由於處理器陷入並執行幾個步驟的操作,它比對齊的變體長10或100倍,然後從陷阱。如果你還運行多個線程,你也可能會發現變量的更新不是以原子方式完成的,所以你得到的值是「一半一半」,這可能會導致非常奇怪的效果。這並不是一個確定的「事情有點不對,但不是立即明顯的方式」的潛在情景的清單。

我的建議是:不要混淆對齊方式,並儘可能絕對不要寫代碼來訪問未對齊的元素。它可能會回來並咬你早晚......