C语言结构体字节对齐
? 默認字節對齊
C語言結構體字節對齊是老生常談的問題了,也是高頻面試題,現在我們來深入研究這個問題,徹底弄懂到底是怎么回事,給你一個結構體定義和平臺機器位數就能手動計算出結構體占用字節數,現在我們不使用宏#pragma pack,采用默認字節對齊方式。
先拋出結論:
在一個結構體中第一個成員變量放在偏移為0的位置,以后的變量都存儲在該變量占用字節數整數倍的地址上。
結構體總大小,必須是內部最大成員變量的整數倍,不足的補齊。
好了,現在我們直接寫個小程序驗證并分析是否真是這樣一回事。
struct?st{short?a1;short?a2;short?a3; };struct?st2{long?a1;short?a2; };這里我們定義了兩個很簡單的結構體,short占用2個字節,struct st我們一眼就知道大小了6個字節,但是struct st2呢?筆者電腦是64位,那么long占用8個字節,short占用2個字節。我們先來按照結論進行分析,在struct st2中成員變量a1在偏移0處存儲且占用8個字節,成員變量a2占用2個字節,由于8是2的倍數,所以a2在偏移8的位置存儲,又因為有結論2,我們根據結論2可以得出,struct st2必須占用8的倍數大小,所以struct st2總大小是16個字節,不足的后面補齊。現在我分別打印出struct st1和struct st2占用字節數大小和struct st2各個成員變量地址,觀察是否和分析的一樣。
int?main()?{struct?st2?st_val2;printf("sizeof(long) = %d\n",?sizeof(long));printf("sizeof(struct st) = %d\n",?sizeof(struct st));printf("sizeof(struct st2) = %d\n",?sizeof(struct st2));printf("st_val2 addr = %p\n", &st_val2);printf("st_val2 a1 addr = %p\n", &st_val2.a1);printf("st_val2 a2 addr = %p\n", &st_val2.a2);return?0; }編譯運行輸出:
sizeof(long) =?8 sizeof(struct?st) =?6 sizeof(struct?st2) =?16 st_val2 addr =?0x7ffee107f3b8 st_val2 a1 addr =?0x7ffee107f3b8 st_val2 a2 addr =?0x7ffee107f3c0現在我們看一下輸出結果,struct st如我們所愿占用6個字節大小,struct st2也按照我們分析的一樣占用16個字節。我們在程序中定義了一個struct st2類型變量st_val2,從輸出中可以看出變量st_val2的a1成員變量和st_val2變量地址一樣,成員變量a2在偏移8處存儲(0x c0 = 0xb8 8)。一切如我們所愿,看起來好像挺簡單的,我們知道C語言有豐富的數據類型,下面我們再定義一個更復雜的結構體。
struct?st3{int?a1;char?a2;short?a3;long?a4;char?a5; };這個結構體包含了大量數據類型成員變量,再復雜的結構體也能按照我們的結論分析到底占用了幾個字節。
在struct st3中int型成員變量a1占用4個字節,在偏移0處存儲,char型成員變量a2占用2個字節那么應該放在2的倍數地址處存儲,a1已經占用了4個字節,所以a2應該在偏移4的地址存儲。
short型成員變量a3占用2個字節,也應該放在2的倍數地址處存儲,所以a3在偏移6的地址處存儲,a2后面填充1個字節。
long型成員變量a4占用8個字節,應該放在8的倍數地址上存儲,前面我們已經知道a3在偏移6的地址處存儲,且占用2個字節8 = 6 2,所以a4應該在偏移8的地址處存儲。
最后一個char型成員變量a5占用一個字節,那么a5在偏移16地址處存儲。
現在我們計算一下struct st3結構體占用空間大小,從a5偏移出計算16 1 = 17。在struct st3中最大成員變量占用8個字節,所以結構體總大小應該是8的倍數,最后結構體總大小是17 7 = 24,這里的7個字節在最后補齊。
我們依舊寫一個小程序輸出struct st3類型變量各個成員變量地址和結構體總大小。
int?main()?{struct?st3?st_val3;printf("sizeof(struct st3) = %d\n",?sizeof(struct st3));printf("st_val3 addr = %p\n", &st_val3);printf("st_val3.a1 addr = %p\n", &st_val3.a1);printf("st_val3.a2 addr = %p\n", &st_val3.a2);printf("st_val3.a3 addr = %p\n", &st_val3.a3);printf("st_val3.a4 addr = %p\n", &st_val3.a4);printf("st_val3.a5 addr = %p\n", &st_val3.a5);return?0; }編譯運行輸出:
sizeof(struct?st3) =?24 st_val3 addr =?0x7ffeed0c33b0 st_val3.a1 addr =?0x7ffeed0c33b0 st_val3.a2 addr =?0x7ffeed0c33b4 st_val3.a3 addr =?0x7ffeed0c33b6 st_val3.a4 addr =?0x7ffeed0c33b8 st_val3.a5 addr =?0x7ffeed0c33c0從輸出我們可以看出,和我們分析的完全一樣。
枚舉類型變量和聯合體類型變量都可以作為結構體的成員變量,在分析這些結構體占用大小時,分析方法和我們上面的一模一樣,只需要把內部任何一種數據類型變量當做一個普通變量看待即可,但是結構體類型成員變量有點不一樣,它不適用于結論2,我們舉個例子。
struct?st4{char?a1[3];int?a2;long?a3;struct?st3?a4; };在struct st4中我們定義了一個struct st3類型成員變量,前面我們已經分析過了struct st3占用24個字節。成員變量a1占用3個字節,成員變量a2占用4個字節,所以a2存儲在偏移4的地址上,在a1后面填充一個字節。成員變量a3占用8個字節,則a3存儲在偏移8的地址上。那么結構體總共占用字節數大小是:8 ? 8 24 = 40。
最后我們寫一個程序驗證一下是否如此。
int?main()?{struct?st4?st_val4;printf("sizeof(struct st4) = %d\n",?sizeof(struct st4));printf("st4 addr = %p\n", &st_val4);printf("st_val4.a1 addr = %p\n", &st_val4.a1);printf("st_val4.a2 addr = %p\n", &st_val4.a2);printf("st_val4.a3 addr = %p\n", &st_val4.a3);printf("st_val4.a4 addr = %p\n", &st_val4.a4);return?0; }編譯運行輸出:
sizeof(struct?st4) =?40 st4 addr =?0x7ffeec1263a0 st_val4.a1 addr =?0x7ffeec1263a0 st_val4.a2 addr =?0x7ffeec1263a4 st_val4.a3 addr =?0x7ffeec1263a8 st_val4.a4 addr =?0x7ffeec1263b0和我們分析的一模一樣。
聲明:
本文于網絡整理,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯系我們刪除或授權事宜。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的C语言结构体字节对齐的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 盗贼练级天赋(魔兽怀旧盗贼练级天赋)
- 下一篇: 京东购物卡使用方法(京东购物卡使用方法教