關於C 位元組對齊的分析與理解

2021-08-25 06:48:23 字數 2529 閱讀 9557

一、為什麼要進行位元組對齊?

簡單來說就是提高cpu對記憶體的訪問效率。為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;然而,對齊的記憶體訪問僅需要一次訪問。

不同的平台(cpu)和編譯器對位元組對齊的處理是不一樣的,但是原理上大同小異。

一般來說是不需要太過關注位元組對齊的,因為編譯器會自動幫助我們完成。但是某些時候,位元組對齊可能是非常隱蔽的bug的誘因。所以,了解其規則是有必要的。

二、基本原則:

對齊值:乙個變數的對齊值取的是自身長度大小和通過#pragma pack(n)指定的對齊值(沒有指定的話,預設為8)中較小的

圓整值:編譯器會對結構體進行圓整(即,在結構體最末填充一定位元組),圓整值的大小(也可以簡單理解為結構體最後乙個變數將占用的大小)取的是結構體中最寬的基本型別和通過#pragma pack(n)指定的對齊值中較小的

1) 結構體的首位址能夠被其最寬基本型別成員長度和通過#pragma pack(n)指定的對齊值之間較小的值所整除;

2) 結構體每個成員相對於結構體首位址的偏移量都是其對齊值的整數倍,如有需要編譯器會在成員之間加上填充位元組;

3) 結構體的總大小為結構體圓整值的整數倍,如有需要編譯器會在最末乙個成員之後加上填充位元組。

三、例項分析:

a、基本對齊例子

1、struct test1 {

char a;

int i;

char c;

sizeof(test1) = 12

分析:變數i會進行位元組對齊,對齊值為4,編譯器會在a和i之間填充3位元組。最後編譯器會對結構體進行圓整,在結構體最後填充3位元組(因為結構體中最大的基本型別為int,長度為4位元組)。

2、上例中,如果加上 #pragma pack(2)

則,sizeof(test1) = 8

分析:同樣成員變數i會進行位元組對齊,但是由於指定的對齊長度為2,並且比int型別長度4要小,所以對齊值為2。由於指定了對齊值2,所以變數c後會再填充1位元組,以進行圓整。

如果c的型別為short,則sizeof(test1) = 8, 因為short的長度為2,不需要再進行圓整。

如果c的型別為int ,則sizeof(test1) = 10,同樣不需要進行圓整,總大小=2+4+4

3、上例中,如果加上 #pragma pack(8) 或 如果加上 #pragma pack(4), 則,依然 sizeof(test1) = 12

b、另外乙個例子

1、struct test2 {

char a;

double d;

int i;

分析: sizeof(test2) = 24 = 8 + 8 + 8 對齊值=8,圓整值=8,所以變數a後會填充7位元組,變數i後會填充4位元組

如果加上 #pragma pack(8),結果也是一樣的。

如果加上 #pragma pack(4),則 sizeof(test2) = 16 = 4 + 8 + 4

c、結構體之間的對齊

1、 struct test3 {

test1 t1;

test2 t2;

sizeof(test3) = 40

分析: sizeof(test1) = 4 + 4 + 4 = 12 sizeof(test2) = 8 + 8 + 8 = 24

由於原則1,test2的最寬基本型別為double,長度為8,則test2的首位址應該能被8整除。所以在test1和test2之間被填充了4位元組。注意,這裡看的是基本型別的寬度而不是結構體的總長度,即便test1或test2中再巢狀結構體或包含陣列,最終看的也只是其中的乙個基本型別。

2、如果加上 #pragma pack(4),則 sizeof(test3) =28

分析:sizefo(test1) = 4 + 4 + 4 = 12 sizeof(test2) = 4 + 8 + 4 = 16

由於指定了對齊值4,再看原則1時,test2的首位址應該能被4整除(因為指定對齊值4小於最寬基本型別8)。所以結構體之間不需要再填充位元組。

d、列舉間的對齊

1、union u1 {

int i;

char c;

union u2 {

test1 t1;

double d;

struct test4 {

u1 uu1;

u2 uu2;

sizeof(u1) = 4

sizeof(u2) = 16

sizeof(test4) = 24

分析:test1的大小為12,但是由於u2中的最寬基本型別double為8,所以最後u2實際的圓整大小為8位元組,故雖然test1的大小為12,但是u2聯合體所占用的記憶體空間並不僅僅是聯合體中最長的成員,而是圓整後的16位元組;

同樣,u2聯合體的首位址也應該是8的倍數,而不是看test1的大小,故uu1和uu2之間會再被填充4位元組,所以test4的大小為24

四、總結

通過之前的例子和分析可見,只要掌握了位元組對齊的原則,萬變不離其宗。簡單總結一下就是:乙個變數的對齊看的是自身長度和指定對齊值之間較小的;結構體的對齊(包括頭和尾)看的是結構體中最大基本型別的長度和指定對齊值之間較小的。

關於位元組對齊的理解

位元組對齊的剖析 一 需要了解的名詞和概念 1 資料型別自身的對齊值 即資料本身所佔位元組長度。2 結構體或類的自身對齊值 即其中資料成員型別對齊值的最大值。3 指定對齊值 由程式設計人員通過 pragma pack value 指定的value值,通過 pragma pack 解除。4 結構體 類...

關於位元組對齊的理解

結構體對齊 有的時候,在腦海中停頓了很久的 顯而易見 的東西,其實根本上就是錯誤的。就拿下面的問題來看 struct t 使用sizeof t 將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個位元組。實 踐出真知,在vc6中測試了下...

關於位元組對齊的一些理解

1 基本資料對齊 在x86,32位系統下基於microsoft borland和gnu的編譯器,有如下資料對齊規則 a 乙個char 占用1 byte 變數以1 byte對齊。b 乙個short 占用2 byte 變數以2 byte對齊。c 乙個int 占用4 byte 變數以4 byte對齊。d ...