柚子快報激活碼778899分享:C語言----字節(jié)對齊
柚子快報激活碼778899分享:C語言----字節(jié)對齊
一:字節(jié)對齊的概念
? ? ? ? 針對字節(jié)對齊,百度百科的解釋如下:
????????字節(jié)對齊是字節(jié)按照一定規(guī)則在空間上排列,字節(jié)(Byte)是計算機信息技術(shù)用于計量存儲容量和傳輸容量的一種計量單位,一個字節(jié)等于8位二進制數(shù),在UTF-8編碼中,一個英文字符等于一個字節(jié),字節(jié)按照一定規(guī)則在空間上排列就是字節(jié)對齊。
? ? ? ? 上面就提到按照一定規(guī)則,那規(guī)則是什么,按什么規(guī)則去對齊,帶著這個疑問往下走
二:為什么要字節(jié)對齊
? ? ? ? 我們?yōu)槭裁匆M行字節(jié)對齊,不對齊會有什么后果,在計算機中我們?nèi)魏我粋€動作無非就是保證程序的正確性,提高程序的性能和可靠性。
? ? ? ? 1,平臺的硬要求,必須要字節(jié)對齊
????????某些平臺對特定類型的數(shù)據(jù)只能從特定地址開始存取,而不允許其在內(nèi)存中任意存放。例如,Motorola 68000 處理器不允許16位的字存放在奇地址,否則會觸發(fā)異常,因此在這種架構(gòu)下編程必須保證字節(jié)對齊。
? ? ? ? 2,提高程序的性能
? ? ? ? 字節(jié)對齊如何能提高程序的性能?CPU內(nèi)部有幾個重要的部件決定了CPU一次能處理的字節(jié)和可訪問的內(nèi)存大小。寄存器,ALU和數(shù)據(jù)總線的位數(shù),這些共同決定了CPU的字長,常見CPU的字長有4位,8位,16位,32位和64位。字長越多,則CPU內(nèi)部硬件規(guī)模和造價越高。如果CPU字長是16位。它的寄存器和總線也是16位。那么它一次處理的數(shù)據(jù)長度就為2字節(jié)。
? ? ? ? 當(dāng)訪問一個變量時,當(dāng)該變量的地址為偶地址(即字變量的低字節(jié)在偶地址單元,高字節(jié)在奇地址單元),則需要一個總線周期訪問該字變量;如果該字變量的地址為奇地址(即字變量的低字節(jié)在奇地址單元,高字節(jié)在偶地址單元),則需要用兩個連續(xù)的總線周期才能訪問該字變量,每個周期訪問一個字節(jié)。
? ? ? ? 字節(jié)對齊讓CPU讀取數(shù)據(jù)的效果高了,這就解釋了為什么字節(jié)對齊能提高程序的性能。
? ? ? ? 3,節(jié)省程序的內(nèi)存
? ? ? ? 下面我們以一個實際的例子來看看字節(jié)對齊如何節(jié)省內(nèi)存
#include
#include
struct byte1
{
char a;
int b;
short c;
};
struct byte2
{
char a;
short c;
int b;
};
int main()
{
// please write your code here
printf("struct byte1 size:%d\n",sizeof(struct byte1));
printf("struct byte2 size:%d\n",sizeof(struct byte2));
}
?可以看到,同樣是存儲一個char,一個int,一個short,結(jié)構(gòu)體中順序不一樣,結(jié)構(gòu)體的所占的空間也不一樣。之所以出現(xiàn)上述結(jié)果,就是因為編譯器要對數(shù)據(jù)成員在空間上進行對齊
三:字節(jié)對齊規(guī)則
1,基本類型對齊規(guī)則
基本類型包括char、int、float、double、short、long等基本數(shù)據(jù)類型。CPU位數(shù)不同所占的字節(jié)數(shù)也不一樣,如下圖所示
?????????對齊要求:起始地址為其長度的整數(shù)倍即可。如,int類型的變量起始地址要求為4的整數(shù)倍,char類型的變量只占一個字節(jié),那起始地址放哪都行。
2,結(jié)構(gòu)體對齊規(guī)則
1>每個數(shù)據(jù)成員的起始位置必須是自身大小的整數(shù)倍;?
2>結(jié)構(gòu)體總大小必須是結(jié)構(gòu)體成員中最大的對齊模數(shù)的整數(shù)倍;
3>?結(jié)構(gòu)體包含數(shù)組時,按單個類型對齊方式;
4>共用體union取成員的最大內(nèi)存,但包含在結(jié)構(gòu)體內(nèi)時,按union內(nèi)部最大類型字節(jié)數(shù)的整數(shù)倍開始存儲;
struct byte1
{
char a;
int b;
short c;
};
結(jié)構(gòu)體大?。?2 解釋:char占一個字節(jié),int占四個字節(jié),由于int的起始地址要在4的倍數(shù)上,char后邊補齊3個字節(jié),shor占兩個字節(jié),但是整個結(jié)構(gòu)體大小要是最大的對齊模數(shù)的整數(shù)倍,即4的倍數(shù),所以補兩個字節(jié),一共12個字節(jié)
struct byte2
{
char a;
short c;
int b;
};
結(jié)構(gòu)體大?。?
解釋:char占一個字節(jié),short占兩個字節(jié),由于short的起始地址要在2的倍數(shù)上,char后邊補齊1個字節(jié),int占四個字節(jié),剛好在4的倍數(shù)上,所以總共8個字節(jié)
那結(jié)構(gòu)體里嵌套結(jié)構(gòu)體呢?
結(jié)構(gòu)體包含另一個結(jié)構(gòu)體成員,則被包含的結(jié)構(gòu)體成員要從其原始結(jié)構(gòu)體內(nèi)部的最大對齊模數(shù)的整數(shù)倍地址開始存儲(比如struct a里含有struct b,b中有char、double 、int?元素,那么b應(yīng)該從8(double)的整數(shù)倍開始存儲)
結(jié)構(gòu)體嵌套共同體
結(jié)構(gòu)體包含共用體成員,則該共用體成員要從其原始共用體內(nèi)部成員中的最大對齊模數(shù)的整數(shù)倍地址開始存儲
結(jié)構(gòu)體最后包含0數(shù)組
struct byte2
{
char a;
short c;
int b;
double d[0];
};
結(jié)構(gòu)體最后包含0數(shù)組,那0數(shù)組占空間嗎?長度為0的數(shù)組的主要用途是為了滿足需要可變長度的結(jié)構(gòu)體,具體用法是在一個結(jié)構(gòu)體的最后,申明一個長度為0的數(shù)組,就可以使得這個結(jié)構(gòu)體是可變長的。對于編譯器來說,此時長度為0的數(shù)組并不占用空間,因為數(shù)組名本身不占空間,它只是一個偏移量,數(shù)組名這個符號本身代表了一個不可修改的地址常量。
3,共同體對齊規(guī)則
共同體的內(nèi)存除了取最大成員內(nèi)存外,還要保證是所有成員類型size的最小公倍數(shù)。
union byte3
{
char a;
short c[5];
int b;
};
?共同體byte3中最大成員就是short c[5],占10個字節(jié),由于要保證是所有成員類型size的最小公倍數(shù),即4個倍數(shù),所以是12
4,存在#pragma pack宏的對齊規(guī)則
#pragma pack(n)//編譯器將按照n個字節(jié)對齊
#pragma pack()//取消自定義字節(jié)對齊方式
******對齊規(guī)則******
結(jié)構(gòu)體、聯(lián)合、類的結(jié)構(gòu)成員,第一個放在偏移為0的地方,以后每個數(shù)據(jù)成員的對齊,按照#pragma pack指定的數(shù)值和自身對齊模數(shù)中最小的那個。
結(jié)構(gòu)體的大小是#pragma pack指定的數(shù)值的整數(shù)倍。
#pragma pack(4)
typedef struct
{
int age;
char name[0];
double a;
} Person;
#pragma pack();//結(jié)束#pragma pack(4)對齊。 如果沒有結(jié)束,aa也按照#pragma pack(4)對齊
typedef struct
{
double age;
Person k;
} aa;
int m=sizeof(Person); // m=12, 按照4字節(jié)對齊
int n=sizeof(aa); // n=24, 按照8字節(jié)對齊 按照#pragma pack(4)對齊的話,n=20
5,位域字節(jié)對齊規(guī)則
“位域”是把一個字節(jié)中的二進位劃分為幾個不同的區(qū)域,并說明每個區(qū)域的位數(shù)。使用位域的主要目的是壓縮存儲。
位域列表的形式為:?類型說明符 位域名:位域長度(單位:位 bite)
如:struct bs ? ? ? { ? ? ? ? ? ?int a:8; ? ? ? ? ? ?int b:2; ? ? ? ? ? ?int c:6; ? ? ? ?} data; 其中位域a占8位,位域b占2位,位域c占6位。
位域說明:
1.?一個位域必須存儲在同一個字節(jié)中,不能跨兩個字節(jié)。如一個字節(jié)所??臻g不夠存放另一位域時,應(yīng)從下一單元起存放該位域。
2. 由于位域不允許跨兩個字節(jié),因此位域的長度不能大于一個字節(jié)(8位)的長度,也就是說不能超過8位二進位。 3. 位域可以無位域名,這時它只用來作填充或調(diào)整位置。無名的位域是不能使用的。例如:?int :2 ?
位域?qū)R規(guī)則
1) 如果相鄰位域字段的類型相同,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止;
2) 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數(shù)倍;
3) 如果相鄰的位域字段的類型不同,從新的存儲單元開始,偏移量為其類型大小的整數(shù)倍,即不壓縮;(各編譯器的具體實現(xiàn)有差異,VC6采取不壓縮方式,Dev-??
? ? ?C++采取壓縮方式)
4) 如果位域字段之間穿插著非位域字段,則不進行壓縮;
5)?整個結(jié)構(gòu)體的總大小為最寬基本類型成員大小的整數(shù)倍。
例題:
(1)typedef?struct??AA { ???????unsigned?int?b1:5; ???????unsigned?int?b2:5; ???????unsigned?int?b3:5; ???????unsigned?int?b4:5; ???????unsigned?int?b5:5; }AA;
sizeof(AA)= 4?
【解析】參考規(guī)則 1)。由于相鄰成員類型相同,unsigned?int為 4 個字節(jié),b1占5位,b2加上b1的位數(shù)之和為10位,不超過4字節(jié),因此b2接著b1繼續(xù)存儲;
? ? ? 同理b3、b4、b5的類型相同,位數(shù)之和不超過4字節(jié),因此接著b2繼續(xù)存儲,總位數(shù)為25位。
? ? ? 由于結(jié)構(gòu)體的大小是最寬類型成員的整數(shù)倍,因此25位之后的補0,直到補滿4字節(jié)。
(2)typedef?struct??AA { ???????unsigned?int?b1:5; ???????unsigned?int?b2:5; ???????unsigned?int?b3:5; ???????unsigned?int?b4:5; ???????unsigned?int?b5:5; ???????unsigned?int?b6:5; ???????unsigned?int?b7:5; }AA; ? ?sizeof(AA)= 8?
【解析】參考規(guī)則 1) 和規(guī)則 2) 。由于相鄰成員類型相同,unsigned?int為 4 個字節(jié)(32位),當(dāng)存儲到 b7 時,b7和b6之前的位數(shù)相加超過4字節(jié),
因此b7從新的存儲單元開始存儲。
即b1~b6?存儲在 第0~29位,第30、31位補0,b7從下一個 4字節(jié)存儲單元 開始存儲5位,剩下的補0。
?(3)struct test1
{
char a:1;
char :2;
long b:3;
char c:2;
};
?sizeof(test1)= 12
【解析】
char a:1; //用一個字節(jié)去存儲
char :2; //空域。因為與前面的a的類型相同,而兩個位域的位寬相加仍然少于8位,所以依然用1個字節(jié)表示
long b:3; //long類型的位寬是4個字節(jié),與前面的char類型不同,所以b與a之間偏移4個字節(jié),它們之間自動補充3個字節(jié)
char c:2; //因為c與b又不同型,以test1中的最長的long類型的位寬進行偏移,所以雖然char只用1個字節(jié)就夠了,但依然要占4個字節(jié)。
結(jié)構(gòu)體總長以最長的類型位寬做為偏移量,最長的是long型,占4位,所以不同類型之間應(yīng)該是4個字節(jié)的偏移,即test1應(yīng)該是4字節(jié)的整數(shù)倍?!?/p>
總共是12字節(jié)。
柚子快報激活碼778899分享:C語言----字節(jié)對齊
精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。