C語言 位元組對齊 總結

2021-10-09 16:46:22 字數 3456 閱讀 1304

struct student

data;

如上結構體變數 data 佔多少位元組?char 佔 1 位元組,int 佔 4 位元組,所以總共佔 5 位元組嗎?我們寫乙個程式驗證一下:

#include

struct student

data;

int main(void)

輸出結果是:

00427e68, 00427e6c

8我們看到 data 不是佔 5 位元組,而是佔 8 位元組。變數 a 的位址是從 00427e68 到 00427e6b,佔 4字 節;變數 b 的位址是從 00427e6c 到 00427e6f,也佔 4 位元組。b 佔 4 位元組我們能理解,但 a 是 char 型,char 型不是佔 1 位元組嗎,這裡為什麼佔 4 位元組?其實不是它佔了 4 位元組,它佔的還是 1 位元組,只不過結構體中有乙個位元組對齊的概念。

什麼叫位元組對齊?我們知道結構體是一種構造資料型別,裡面可以有不同資料型別的成員。在這些成員中,不同的資料型別所佔的記憶體空間是不同的。那麼系統是怎麼給結構體變數的成員分配記憶體的呢?或者說這些成員在記憶體中是如何儲存的呢?通過上面這個例子我們知道肯定不是順序儲存的。

那麼到底是怎麼儲存的呢?就是按位元組對齊的方式儲存的!即以結構體成員中佔記憶體最多的資料型別所佔的位元組數為標準,所有的成員在分配記憶體時都要與這個長度對齊。我們舉乙個例子:我們以上面這個程式為例,結構體變數 data 的成員中佔記憶體最多的資料型別是 int 型,其佔 4 位元組的記憶體空間,那麼所有成員在分配記憶體時都要與 4 位元組的長度對齊。也就是說,雖然 char 只佔 1 位元組,但是為了與 4 位元組的長度對齊,它後面的 3 位元組都會空著,即:

a 空 空 空

b所謂空著其實也不是裡面真的什麼都沒有,它就同定義了乙個變數但沒有初始化一樣,裡面是乙個很小的、負的填充字。為了便於表達,我們就暫且稱之為空好了。

如果結構體成員為:

struct student

data;

那麼這三個成員是怎麼對齊的?a 和 b 後面都是空 3 位元組嗎?不是!如果沒有 b,那麼 a 後面就空 3 位元組,有了 b 則 b 就接著 a 後面填充。即:

a b 空 空

c所以這時候結構體變數 data 仍佔 8 位元組。我們寫乙個程式驗證一下:

#include

struct student

data;

int main(void)

輸出結果是:

00427e68, 00427e69, 00427e6c

8這時我們發現乙個問題:所有成員在分配記憶體的時候都與 4 位元組的長度對齊,多個 char 型別時是依次往後填充,但是 char 型後面的 int 型為什麼不緊接著後面填充?為什麼要另起一行?也就是說,到底什麼時候是接在後面填充,什麼時候是另起一行填充?

我們說,所有的成員在分配記憶體時都要與所有成員中佔記憶體最多的資料型別所佔記憶體空間的位元組數對齊。假如這個位元組數為 n,那麼對齊的原則是:理論上所有成員在分配記憶體時都是緊接在前乙個變數後面依次填充的,但是如果是「以 n 對齊」為原則,那麼,如果一行中剩下的空間不足以填充某成員變數,即剩下的空間小於某成員變數的資料型別所佔的位元組數,則該成員變數在分配記憶體時另起一行分配。

下面再來舉乙個例子,大家覺得下面這個結構體變數data佔多少位元組?

struct student

data;

首先最長的資料型別佔 4 位元組,所以是以 4 對齊。然後 a 佔 1 位元組,b 接在 a 後面佔 1 位元組,c 接在 b 後面佔 1 位元組,d 接在 c 後面佔 1 位元組,此時滿 4 位元組了,e 再來就要另起一行。f 想緊接著 e 後面分配,但 e 後面還剩 3 位元組,小於 int 型別的 4 位元組,所以 f 另起一行。即該結構體變數分配記憶體時如下:

a b c d

e 空 空 空

f即總共佔 12 位元組。我們寫乙個程式驗證一下:

#include

struct student

data;

int main(void)

輸出結果是:

00427e68, 00427e69, 00427e6a, 00427e6b, 00427e6c, 00427e70

12struct student

data;

即將原來第二個和第三個宣告交換了位置,大家看看現在 data 變數佔多少位元組?沒錯,是 12 位元組。首先最長型別所佔位元組數為 4,所以是以 4 對齊。分配記憶體的時候 a 佔 1 位元組,然後 b 想緊接著 a 後面儲存,但 a 後面還剩 3 位元組,小於 b 的 4 位元組,所以 b 另起一行分配。然後 c 想緊接著 b 後面分配,但是 b 後面沒空了,所以 c 另起一行分配。所以總共 12 位元組。記憶體分配圖如下所示:

a 空 空 空

bc 空 空 空

下面寫乙個程式驗證一下:

struct student

data;

int main(void)

輸出結果是:

00427e68, 00427e6c, 00427e70

12我們看到,同樣三個資料型別,只不過交換了一下位置,結構體變數data所佔的記憶體空間就由8位元組變成12位元組,多了4位元組。這就告訴我們,在宣告結構體型別時,各型別成員的前後位置會對該結構體型別定義的結構體變數所佔的位元組數產生影響。沒有規律的定義會增加系統給結構體變數分配的位元組數,降低記憶體分配的效率。但這種影響對作業系統來說幾乎是可以忽略不計的!所以我們在寫程式的時候,如果有心的話,宣告結構體型別時就按成員型別所佔位元組數從小到大寫,或從大到小寫。但是如果沒有按規律書寫的話也不要緊,宣告結構體型別時並非一定要從小到大宣告,只是為了說明「位元組對齊」這個概念!而且有時候為了增強程式的可讀性我們就需要沒有規律地寫,比如儲存乙個人的資訊:

struct student

data;

正常的思維是將「性別」放在「年齡」後面,但如果為了記憶體對齊而交換它們的位置,總讓人覺得有點彆扭。所以我說「盡量」有規律地寫!

這時又有人會提出乙個問題:「上面這個結構體變數 data 中有成員 char name[10],長度最長,是 10,那是不是要以 10 對齊?」不是,char a[10] 的本質是 10 個 char 變數,所以就把它當成 10 個 char 變數看就行了。所以結構體變數 data 中成員最長型別佔 4 位元組,還是以 4 對齊。該結構體變數分配記憶體時情況如下:

name[0] name[1] name[2] name[3]

name[4] name[5] name[6] name[7]

name[8] name[9] 空 空

age*** 空 空 空

float

總共 24 位元組,我們寫乙個程式驗證一下:

#include

struct student

data;

int main(void)

輸出結果是:

00427e68, 00427e69, 00427e6a, 00427e6b, 00427e6c, 00427e6d, 00427e6e,

00427e6f, 00427e70, 00427e71, 00427e74, 00427e78, 00427e7c

24

c語言位元組對齊

現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特 定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。基本資料型別自身對齊,也叫自然對齊。就是說...

C語言位元組對齊

一 概念 對齊跟資料在記憶體中的位置有關。如果乙個變數的記憶體位址正好位於它長度的整數倍,他就被稱做自然對齊。比如在32位cpu下,假設乙個整型變數的位址為0x00000004,那它就是自然對齊的。二 為什麼要位元組對齊 需要位元組對齊的根本原因在於cpu訪問資料的效率問題。假設上面整型變數的位址不...

C語言位元組對齊

一 概念 對齊跟資料在記憶體中的位置有關。如果乙個變數的記憶體位址正好位於它長度的整數倍,他就被稱做自然對齊。比如在32位cpu下,假設乙個整型變數的位址為0x00000004,那它就是自然對齊的。二 為什麼要位元組對齊 在c語言中,結構是一種復合資料型別,其構成元素既可以是基本資料型別 如int ...