結構體struct的自然對齊問題(經典)

來源:互聯網
上載者:User

結構體struct的自然對齊問題
下面的機構體
struct A
{
    char c;
    int i;
    char cc;
};
它的sizeof()是多少呢? 如果是緊湊對齊的話,當然是sizeof(char)+sizeof(int)+sizeof(char); 但編譯器預設編譯的卻不是緊湊對齊的,在32-bit的機器上編譯結果是12, 這是一個char佔用了一個int的空間,換句話說,在c和i之間有三個空餘的byte! 這就是自然對齊的效果。
為什麼要自然對齊呢?
當初百度的gg電面我的時候,我胡亂的解釋了一下,居然是對的,真是佩服我的扯淡能力。原來x86架構下的cpu訪存時,是需要地址對齊的,舉個例子,取short型時,地址需要是2的倍數,取int型是地址需要是4的倍數,如果不是的話,則可能降低cpu訪存的效率。例,一個int的地址是0x03的話,先是按地址0x00取int的第一個byte,然後按地址0x04取剩下的三個byte,所以原本一次訪存搞定的事情,卻做了兩次,簡直是脫褲子放屁--多此一舉嘛,哈哈。
怎麼計算自然對齊的sizeof()呢?
這個才是面試官的殺手鐧,哈哈。
其實就是一個規律--這個取決於cpu的字長
在32bit的cpu上,對齊的單位是4個byte,64bit的我沒有試過,誰有環境搞一下哈。
例:
struct B
{
    char ca;
    char cb;
    char cc[10];//這段char+char數組是連在一起的,按char對齊
    int i;
    char cd[3];//有一個byte是空著的哦
};
sizeof()是20; 注意,連續的char總是按char對齊,多出部分的char才是按int對齊的,細心的你,也許發現linux上的網路頭部的標頭檔中,比如ip的tcp的,都是用char或char數組定義的,這樣就避免了自然對齊的問題,是的總是按char的緊湊對齊,增強程式的可移植性。我曾經就犯過這樣的錯誤,解析網路頭部的時候,struct裡面同時出現int和char,自然對齊的結果是總是無法正確的解析出arp協議,鬱悶我半年才發現這個bug。其實,這不是bug,這是語言的特性(引自《C專家》)。
網路上也有別的朋友說,是按照結構體裡面最大的單元對齊的,這種說法是錯誤的,原因在於,他舉的case全是int最大,而32bit的cpu總是按32-bit對齊正好是int的長度,這樣就產生了錯誤的認識。

struct C
{
    double d;
    char c;
};
sizeof()的大小是12,不是2*sizeof(double)哦。
struct D
{
    struct B b;
    struct C c;
};
sizeof()的大小就是sizeof(B)+sizeof(C)的大小啦,可不是2*sizeof(B)哦;
怎麼讓結構體緊湊對齊呢?
gcc提供一個選項-fpack-struct,可是實現緊湊對齊的編譯,其他平台可以藉助#pragma pack來搞定,具體看網頁http://www.mscenter.edu.cn/blog/mingge/archive/2005/12/10/7655.html

 

----------------------------------------------------------------------------------------------------------------------

結構體以其內部最大的基礎資料型別 (Elementary Data Type)和編譯器位元組對齊設定中的較小值為單位對齊。

比如:struct A{ int i; char c;};就以int型(4位元組)對齊,所以整個結構體大小為8.

而:struct B{char k;char c;};以char型(1位元組)對齊,所以整個結構體大小為2。

基礎資料型別 (Elementary Data Type)以該類型長度和編譯器位元組對齊設定中的較小值對齊。

VC中#pragma pack(1)設定位元組以1位元組對齊。預設是以的位元組對齊。且只能設定為2的冪。

例如:struct C{char k;int i;};的大小為8,且i的地址是從k的後面三個位元組開始的,因為int以4位元組對齊。

再如:#pragma pack(1)      struct D{char k;int i;};    #pragma pack() //恢複;的大小為5,因為int是以1位元組對齊的。且整個結構體也受int型的對齊大小影響而變成1位元組對齊。

 

----------------------------------------------------------------

MIPS體繫結構

最近問我MIPS體繫結構相關問題的人越來越多,在這裡小結一下。
一般在職業有段者水平的MIPS體繫結構問題,都能在這裡找到答案。

1.
Q: MIPS有多少一般用途的寄存器?
A: 32個。

2.
Q: 我在看反組譯碼代碼的時候,看到一些寄存器名叫zero, a1, a2...還有sp, ra這樣的名字。為什麼給他們起這些名字呢?
A: MIPS的通用寄存器中,按照編譯器的通常的約定,某些寄存器是做專門用途的,比如sp就是堆棧指標,ra是函數調用的返回地址等等。當然你也可以不按照這些約定編程,例如用$2存放堆棧指標,$3存放返回地址,但這樣的程式,和標準庫連結就不能工作了。

3.
Q: 為什麼MIPS的SP寄存器也是通用寄存器呢?而且MIPS似乎沒有專門的壓棧/出棧指令啊。
A: 這是MIPS這樣的RISC處理器,同x86為代表的CISC處理器的重大區別之一。RISC沒有專門的硬體實現的堆棧寄存器/指令,改為軟體實現,在函數入口堆棧指標遞減,堆棧向低地址生長,返回處恢複堆棧值,銷毀堆疊框架。

4.
Q: MIPS的堆棧用軟體實現,那麼,MIPS的函數調用開銷會更大嗎?
A: 這是x86為首的CISC支援者,經常詬病RISC的一點。但是,實際上,我們知道,MIPS使用了4個GPR(一般用途寄存器)來傳遞前4個Word的函數參數,而x86隻有EAX一個寄存器用於傳遞函數參數。所以,如果函數的參數小於或等於4個word,那就不需要使用棧。我們知道,大多數函數的參數都在4 個word以內。——所以,這一點不比太擔心。另外,寫太多參數的函數時,建議使用結構體傳遞這些參數。

5.
Q: MIPS的lh, lb這樣的指令,會改變寄存器裡的前2個/1個位元組,還是後2個/1個位元組?
A:一般來說是低位。

6.
Q: MIPS是大端(Big-endian)的,還是小端的(Little-endian)?
A: 這是可以配置的。一般來說我們都使用大端模式,因為幾乎所有的網路通訊協定,資料包中的資料欄位均以大端模式封裝。

7.
Q: 我在新聞報道看到“龍芯”和MIPS的指令95%相同,那麼到底是哪部分不相同呢?
A: MIPS的四條“非對齊載入/儲存”指令,是受專利法保護的,龍芯在沒有獲得授權的情況下不能支援這四條指令。

8.
Q: 什麼是非對齊載入/儲存指令?什麼情況下用這些指令呢?
A: MIPS的記憶體訪問要求位元組對齊。譬如,4位元組訪問指令,要求訪問的開始地址能被4整除,如0x8100223C. 如果訪問0x8100223D這個地址,就會發生一個異常(Exception)。MIPS處理器在處理這個異常時,把這樣一次載入拆分為兩次非對齊的載入來實現。

9.
Q: 可是x86上,似乎沒有這樣的限制啊?
A: 其實x86也有這個問題,非對齊訪問會被拆成兩次執行。只不過這一切都由硬體來完成,對代碼層級透明——這樣,一個不理解這個原理的程式員就非常容易在設計資料結構的時候犯下這方面的錯誤,大量非對齊訪問嚴重地影響系統的效能。

 

------------------------------------------------------------------------------------------------------------------------------

Mips CPU 要求記憶體位址必須對齊

1. Mips CPU 只能通過Load/Store兩條指令訪問記憶體
  RISC的指令一般比較整齊,單條指令的功能單一,執行時間比較快。只能對寄存器中的資料運算,儲存空間的定址一般只能通過L/S(Load/Store)進行。一般為等長指令,更便於流水線。
  MIPS為RISC系統,等長指令,每條指令都有相同的長度:32位。其作業碼固定為:6位。其餘26位為若干個運算元。

2. 記憶體位址的對齊
  對於一個32位的系統來說,CPU 一次只能從記憶體讀32位長度的資料。如果CPU要讀取一個int類型的變數並且該變數的起始位不在所讀32位元據的首位,那麼CPU肯定無法一次性讀完這個變數,這時就說這個變數的地址是不對齊的。相反,如果CPU可以一次性讀完一個變數,則說該變數的地址是對齊的。

3. Mips CPU 要求記憶體位址(即Load/Store的操作地址)必須是對齊的
  其實不管是Mips,還是X86,都希望所操作地址是對齊的,因為這樣可以最快速地處理資料。
  不過X86平台可以很容易很快速地處理不對齊的情況,而Mips一旦遇到地址不對齊的變數就會拋出exception,從而調用一大段後續處理代碼,繼而消耗大量的時間。
  因此,不管工作在什麼平台下,程式員都應該養成使記憶體位址對齊的好習慣。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.