1. 程式人生 > >C/C++中的struct位元組對齊問題

C/C++中的struct位元組對齊問題

位元組對齊問題在面試筆試中經常碰到,自己也在這裡經常碰到坑,今天索性把這方面搞清楚,記錄自己這方面的學習過程。

大端小端法

機器的大端小端問題一直是一個常考的點,並且struct的記憶體佈局問題和這個大端小端有很大關係,這裡先看下機器的大端小端問題:
下面通過一張圖來說明問題,假如一個變數int x的值為0x12345678,當在不同的機器上儲存順序是不同的
大端小端圖
可以看到,大端機器上低地址儲存的是高位,小端則恰恰相反。用一個C語言程式來測試你的機器是大端還是小端的好的方式如下:

show_bytes()
{
    int x = 0x12345678;
    unsigned
char *p = (unsigned char*)&x; int i = 0; for(i = 0; i < sizeof(int);i++) { printf("%.2x",p[i]); } printf("\n"); }

這段程式碼可以看出當前系統是大端還是小端,在我的機器上顯示的是78563412,因此我的電腦是小端模式。

struct 與union的對齊規則

  • struct或者union的資料成員對齊規則:第一個放在offset位置為0處,從第二個開始,該元素與前一個元素之間的填充是由該元素字長與#pragma pack(k)(k=1,2,4,8,16)中的k之間的小者來決定。如果本身為兩者之間的小者的整數倍,則不進行填充。即除去第一個元素,其餘的元素的開始位置是由兩者之間的小者的整數倍來決定的
  • 整體填充完畢後,該struct整體大小是由pack(k)指定的k與資料元素裡面最大字長之間的小者決定。
    下面舉幾個例子來說明位元組對齊遵循的規則
#pragma pack(k)//k=1,2,4,8,16
    struct S4 {
        char x1;
        double x2;
        short x3;
        float x4;
        char x5;
    };
  cout<< sizeof(S4) << endl; 

可以列印k分別等於1,2,4,8,16時S4的佔用的大小空間,可以得到的結果分別為

16
18
24
32
32 //和k為8的結果相同

k為1的時候,此時不進行對齊,因此為所有變數的字長之和。下面從k為2的時候開始分析
- k = 2 時,第一個元素從offset為0的地址開始,第二個元素是double佔8個位元組,和當前k=2對比,2較小,又因為第一個元素是char,只佔用一個位元組,因此第二個元素和第一個元素之間需要達到2的倍數,需要填充1個位元組;再看x3,x3佔用2位元組和k=2相等,而x1和x2已經佔用了10位元組,為2的倍數,因此x3和x2之間不填充位元組;再看x4,佔用4位元組,比k=2大,而前三個元素已經12位元組,為2的倍數,因此不需要填充。最後一個元素也不用填充。整體為18位元組。整體18個位元組,是2的倍數,因此最後一個元素不需要填充。下面是記憶體佈局圖:
這裡寫圖片描述
其它的情況和這個類似,可以對比著畫出來。