什麼是對齊?
在C/C++中,數據結構或類的成員變量,並不是按照它們的大小,一個一個緊湊地排列在空間上的。它們是按照一種特定的方法排列的,有可能在兩個成員變量之間插入一個或個byte,以保證每個成員變量的起始位置是都是從某些特定的位置開始的。這就是對齊。單純從語言上描述對齊有些枯燥難以理解,下文將配以例子說明C/C++是基於什麼樣的規則對齊的。
為什麼要對齊?
在大多數平台上,系統從某些特定的位置開始讀數據非常快,而從其它位置讀數據會慢很多。C/C++是一種注重效率的語言,為了使程序速度盡可能地快,選擇犧牲很少的空間,用填充byte的方式保證所有數據的存儲都從這些特定的位置開始,而達到較高的運行速度。
什麼是4字節對齊?
當說到一個結構體n字節對齊,包含2個信息:
(1)結構體的起始地址能被n整除
(2)結構體的總大小能被n整除
當說到一個成員變量是n字節對齊的,說明該變量的起始地址能被n整除。比如某變量的對齊字節數是4,那麼它的首地址的16進制形式一定是以0/4/8/C結尾的。
在實際場景中,n可以是1、2、4、8
規則開始啦。
1.在64位系統中,默認的對齊字節是8。在32位系統中,網上查到的資料有說4也有說8,因為用的是64位系統,沒有驗證過32位的情況。
struct type
{
int a;
long b;
};
int main()
{
type t;
cout<
運行結果:
size = 16
address a = 0x7fffa0b9e9d0
address b = 0x7fffa0b9e9d8
排列方式:
a a a a 0 0 0 0
b b b b b b b b
2.對於整個結構體而言,其整個大小也必須是字節數的倍數,如果不足,後面補充
struct type
{
long a;
int b;
};
int main()
{
type t;
cout<
運行結果:
size = 16
address a = 0x7ffff8bb0840
address b = 0x7ffff8bb0848
排列方式:
a a a a a a a a
b b b b 0 0 0 0
3.可以通過#pragma pack修改默認值,但只能改小,不能改大。
#pragma pack (4)
struct type
{
long a;
int b;
};
int main()
{
type t;
cout<
運行結果:
size = 12
address a = 0x7fffe365d4d0
address b = 0x7fffe365d4d8
排列方式:
a a a a
a a a a
b b b b
4.
對於結構體或類中的某一個成員變量而言,它的對齊按照 #pragma pack指定的數值和這個數據成員自身長度中,比較小的那個進行。
a=數據成員自動長度
b=默認值,取值范圍為1,2,4,8
該數據成員對齊字節=min(a,b)
struct type
{
bool a;
int b;
};
int main()
{
type t;
cout<
運行結果:
size = 8
address a = 0x7fff43062ed0
address b = 0x7fff43062ed4
排列方式:
a 0 0 0
b b b b
5.
對於一個結構體,它的對齊字節取取決於結構中最大的成員與#pragma pack指定的數值
a=結構中最大的數據成員的自動長度
b=默認值,取值范圍為1,2,4,8
該結構體對齊字節=min(a,b)
struct type
{
int a;
bool b;
};
int main()
{
type t;
cout<
運行結果:
size = 8
address a = 0x7fff518d64a0
address b = 0x7fff518d64a4
排列方式:
a a a a
b 0 0 0
6.
默認值等於或超過所有數據成員長度的時候,默認值的大小將不產生任何效果。
a=max(所有數據成員長度)
b=默認值,取值范圍為1,2,4,8
If(b>a)
該結構體對齊字節數為a
7.結構體包含結構體的情況
若某一成員變量是另一個結構體,該成員變量的對齊字節數為成員變量結構體的對齊字節數
例1:
struct byte3
{
char a;
char b;
char c;
};
struct type
{
byte3 a;
byte3 b;
byte3 c;
};
int main()
{
type t;
cout<
運行結果
size = 9
address a = 0x7fff6346cdf0
address b = 0x7fff6346cdf3
address c = 0x7fff6346cdf6
說明:
由於所有結構體中最大的字節長度是1,所以是1字節對齊的。雖然有一個結構體的大小是3,但是還是按照1對齊的。
例2:
struct byte3
{
short a;
char b;
};
struct type
{
byte3 a;
byte3 b;
byte3 c;
};
int main()
{
type t;
cout<
運行結果:
size = 12
address a = 0x7fffff3f1ef0
address b = 0x7fffff3f1ef4
address c = 0x7fffff3f1ef8
說明:
由於所有結構體中最大的字節長度是1,所以結構體之間是2字節對齊的。