C/C++結構體位元組對齊問題
- 1 前言
- 2 舉例
- 3.其他
1 前言
對于結構體位元組對齊問題,我發現我一直有一個誤區,正是這個誤區,給我帶來了很大困擾,今天突然頓悟,在此記錄一下,希望能幫到大家。
2 舉例
#include <stdio.h>
#define field_offset(s,f) (int)(&(((struct s *)0)->f))
struct AD { int a; char b[13]; double c;};
#pragma pack(push)
#pragma pack(1)
struct A1 { int a; char b[13]; double c;};
#pragma pack(2)
struct A2 { int a; char b[13]; double c;};
#pragma pack(4)
struct A4 { int a; char b[13]; double c;};
#pragma pack(8)
struct A8 { int a; char b[13]; double c;};
#pragma pack(16)
struct A16 { int a; char b[13]; double c;};
#pragma pack(pop)
int main()
{
printf("AD.a %d\n",field_offset(AD,a));//AD.a 0
printf("AD.b %d\n",field_offset(AD,b));//AD.b 4
printf("AD.c %d\n",field_offset(AD,c));//AD.c 24
printf("AD sizeof %d\n", sizeof(AD));//AD sizeof 32
printf("\n");
printf("A1.a %d\n",field_offset(A1,a));//A1.a 0
printf("A1.b %d\n",field_offset(A1,b));//A1.b 4
printf("A1.c %d\n",field_offset(A1,c));//A1.c 17
printf("A1 sizeof %d\n", sizeof(A1));//A1 sizeof 25
printf("\n");
printf("A2.a %d\n",field_offset(A2,a));//A2.a 0
printf("A2.b %d\n",field_offset(A2,b));//A2.b 4
printf("A2.c %d\n",field_offset(A2,c));//A2.c 18
printf("A2 sizeof %d\n", sizeof(A2));//A2 sizeof 26
printf("\n");
printf("A4.a %d\n",field_offset(A4,a));//A4.a 0
printf("A4.b %d\n",field_offset(A4,b));//A4.b 4
printf("A4.c %d\n",field_offset(A4,c));//A4.c 20
printf("A4 sizeof %d\n", sizeof(A4));//A4 sizeof 28
printf("\n");
printf("A8.a %d\n",field_offset(A8,a));//A8.a 0
printf("A8.b %d\n",field_offset(A8,b));//A8.b 4
printf("A8.c %d\n",field_offset(A8,c));//A8.c 24
printf("A8 sizeof %d\n", sizeof(A8));//A8 sizeof 32
printf("\n");
printf("A16.a %d\n",field_offset(A16,a));//A16.a 0
printf("A16.b %d\n",field_offset(A16,b));//A16.b 4
printf("A16.c %d\n",field_offset(A16,c));//A16.c 24
printf("A16 sizeof %d\n", sizeof(A16));//A16 sizeof 32
printf("\n");
return 0;
}
如果你認為的結果和上面注釋中的一樣,那你就沒有必要讀下去了。
在上面的例子中,對于A1,A2, A4的結果我都了解,但是對AD,A8,A16我很不了解。
對于AD,我認為結果應該是:
AD.a 0
AD.b 8
AD.c 24
AD sizeof 32
我是這樣想的:AD應該是8位元組對齊的,a是4位元組,b占13位元組,a後面雖然空了4個位元組,但是放不下b,是以應該是a後面補4個位元組,接着放b。b13個位元組,不是8的倍數,是以b後面補3個位元組。接着c占8個位元組。
當然,我上面的想法是錯誤的。可是為什麼會錯呢?
其實,問題出在b的身上。b是一個char型的數組,即類型為char *,但是我們通路的是b的元素,即char,是以,b的自身對齊值為1,而不是13。
之是以這裡出錯,實際上是因為沒有深刻認識到為什麼要位元組對齊。位元組對齊是為了提高CPU通路資料的效率。32位字長的計算機,其CPU一次可以讀寫的資料長度是4個位元組64位計算機則一次可以讀取8個位元組。對于char型數組,隻占據一個位元組,小于計算機一次讀取的位元組數,是以無論其元素放在什麼位址,都可以一次讀取到,便“不需要”位元組對齊。是以,b的元素是可以緊挨着a來放的,是以AD實際空間存放情況應如下圖所示:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR9keRRlTzUEROBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLilTOyEjZwcjZlZmN5EWY4kzYkRDN5gDO4ADNzEjZ5EzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
AD成員中自身對齊值最大的為8, 是以AD的自身對齊值是8;A8的指定對齊值和自身對齊值一樣,相當于沒指定,還是8位元組對齊;A16指定對齊值16大于自身對齊值8,是以還是8位元組對齊。是以AD,A8,A16的結果是一樣的。
3.其他
這是一個C++程式:
#define field_offset(s,f) (int)(&(((struct s *)0)->f))
int main() {
struct alignas(4) Info {
char a;
short b;
char c;
};
std::cout << sizeof(Info) << std::endl;
std::cout << field_offset(Info, a) << std::endl;
std::cout << field_offset(Info, b) << std::endl;
std::cout << field_offset(Info, c) << std::endl;
return 0;
}
剛開始我以為應該是下面這樣的:
是以
sizeof(Info) = 4
。
但運作結果為:
8
0
2
4
可以推斷出,Info的實際存儲情況應該為:
針對此,我有2個問題:
- C++11标準中,alignas不是最小設定8位元組對齊,也就最小是alignas(8),否則設定無效嗎?為什麼還會出現上面的結果呢?
- 如果
設定生效,根據第二節的例子中提到的:結構體的有效對齊值是自身對齊值和指定對齊值中較小者。那麼實際存儲情況像下面這樣(alignas(4)
)啊:sizeof(Info)= 6
是因為C和C++标準不一樣嗎?C語言結構體位元組對齊問題1 前言2 舉例3.其他
後續:經過驗證,我得到了答案。
參考連結:
- 為什麼要位元組對齊:
- 結構體位元組對齊例子
- 位元組對齊基本概念和準則
- 結構體元素偏移量計算