c語(yǔ)言結(jié)構(gòu)體字節(jié)對(duì)齊的實(shí)現(xiàn)方法
1.什么是字節(jié)對(duì)齊
在c語(yǔ)言的結(jié)構(gòu)體里面一般會(huì)按照某種規(guī)則去進(jìn)行字節(jié)對(duì)齊。
我們先看一段代碼:
struct st1 { char name; double age; char sex; }; //32位下 sizeof(struct st1) = 16 //64位下 sizeof(struct st1) = 24 struct st2 { char a; char b; char c; }; //32位和64位下, sizeof(struct st2)都是3個(gè)字節(jié)
從以上結(jié)果可以看出,結(jié)構(gòu)體st1在32位下是按照4個(gè)字節(jié)來(lái)對(duì)齊的,在64位下則是按照8個(gè)字節(jié)來(lái)對(duì)齊的,結(jié)構(gòu)體st2則不管32位還是64位則都是按照1個(gè)字節(jié)對(duì)齊的。
那么我們可以總結(jié)出對(duì)齊規(guī)則如下:
- 在所有結(jié)構(gòu)體成員的字節(jié)長(zhǎng)度都沒有超出操作系統(tǒng)基本字節(jié)單位(32位操作系統(tǒng)是4,64位操作系統(tǒng)是8)的情況下,按照結(jié)構(gòu)體中字節(jié)最大的變量長(zhǎng)度來(lái)對(duì)齊;
- 若結(jié)構(gòu)體中某個(gè)變量字節(jié)超出操作系統(tǒng)基本字節(jié)單位,那么就按照系統(tǒng)字節(jié)單位來(lái)對(duì)齊。
注意:并不是32位就直接按照4個(gè)字節(jié)對(duì)齊,64位按照8個(gè)字節(jié)對(duì)齊。
2.為什么要有字節(jié)對(duì)齊
首先普及一點(diǎn)小知識(shí),cpu一次能讀取多少內(nèi)存要看數(shù)據(jù)總線是多少位,如果是16位,則一次只能讀取2個(gè)字節(jié),如果是32位,則可以讀取4個(gè)字節(jié),并且cpu不能跨內(nèi)存區(qū)間訪問(wèn)。
假設(shè)有這樣一個(gè)結(jié)構(gòu)體如下:
struct st3 { char a; int b; }; //那么根據(jù)我們第1節(jié)所說(shuō)的規(guī)則,在32位系統(tǒng)下,它就應(yīng)該是8個(gè)字節(jié)的。
假設(shè)地址空間是類似下面這樣的:
在沒有字節(jié)對(duì)齊的情況下,變量a就是占用了0x00000001這一個(gè)字節(jié),而變量b則是占用了0x00000002~0x000000005這四個(gè)字節(jié),那么cpu如果想從內(nèi)存中讀取變量b,首先要從變量b的開始地址0x00000002讀到0x0000004,然后再讀取一次0x00000005這個(gè)字節(jié),相當(dāng)于讀一個(gè)int,cpu從內(nèi)存讀取了兩次。
而如果進(jìn)行字節(jié)對(duì)齊的話,變量a還是占用了0x00000001這一個(gè)字節(jié),而變量b則是占用了0x00000005~0x00000008這四個(gè)字節(jié),那么cpu要讀取變量b的話,就直接一次性從0x00000005讀到0x00000008,就一次全部讀取出來(lái)了。
所以說(shuō),字節(jié)對(duì)齊的根本原因其實(shí)在于cpu讀取內(nèi)存的效率問(wèn)題,對(duì)齊以后,cpu讀取內(nèi)存的效率會(huì)更快。但是這里有個(gè)問(wèn)題,就是對(duì)齊的時(shí)候0x00000002~0x00000004這三個(gè)字節(jié)是浪費(fèi)的,所以字節(jié)對(duì)齊實(shí)際上也有那么點(diǎn)以空間換時(shí)間的意思,具體寫代碼的時(shí)候怎么選擇,其實(shí)是看個(gè)人的。
3.手動(dòng)設(shè)置對(duì)齊
什么情況下需要手動(dòng)設(shè)置對(duì)齊:
- 設(shè)計(jì)不同CPU下的通信協(xié)議,比如兩臺(tái)服務(wù)器之間進(jìn)行網(wǎng)絡(luò)通信,共用一個(gè)結(jié)構(gòu)體時(shí),需要手動(dòng)設(shè)置對(duì)齊規(guī)則,確保兩邊結(jié)構(gòu)體長(zhǎng)度一直;
- 編寫硬件驅(qū)動(dòng)程序時(shí)寄存器的結(jié)構(gòu);
手動(dòng)設(shè)置對(duì)齊方式有兩種:
代碼里添加預(yù)編譯標(biāo)識(shí):
//用法如下 #pragma pack(n)//表示它后面的代碼都按照n個(gè)字節(jié)對(duì)齊 struct st3 { char a; int b; }; #pragma pack()//取消按照n個(gè)字節(jié)對(duì)齊,是對(duì)#pragma pack(n)的一個(gè)反向操作 //這里計(jì)算sizeof(st3)=5
上面這兩行其實(shí)就類似于開車的時(shí)候,走到某一段路的時(shí)候,發(fā)現(xiàn)一個(gè)限速60公里的指示牌,過(guò)了那一段路以后,又會(huì)有解除限速60公里的指示牌。
定義結(jié)構(gòu)體時(shí):
//用法如下 struct bbb { char a; int b; }__attribute__((packed));//直接按照實(shí)際占用字節(jié)來(lái)對(duì)齊,其實(shí)就是相當(dāng)于按照1個(gè)字節(jié)對(duì)齊了 //這里計(jì)算sizeof(st3)=5
4.結(jié)構(gòu)體比較方法
可以使用內(nèi)存比較函數(shù)memcpy進(jìn)行結(jié)構(gòu)體比較,但因?yàn)榻Y(jié)構(gòu)體對(duì)齊可能會(huì)有填充位不一致的情況,此時(shí)需要注意:
- 設(shè)置為1個(gè)字節(jié)對(duì)齊,使它沒有空位;
- 事先對(duì)結(jié)構(gòu)體進(jìn)行初始化;
memcpy(char *dest, const char* src, int len); //頭文件#include<string.h>
到此這篇關(guān)于c語(yǔ)言結(jié)構(gòu)體字節(jié)對(duì)齊的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)c語(yǔ)言結(jié)構(gòu)體字節(jié)對(duì)齊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++求解二叉樹的下一個(gè)結(jié)點(diǎn)問(wèn)題
本文將通過(guò)C++求解以下問(wèn)題:給定一個(gè)二叉樹其中的一個(gè)結(jié)點(diǎn),請(qǐng)找出中序遍歷順序的下一個(gè)結(jié)點(diǎn)并且返回。文中示例代碼講解詳細(xì),感興趣的可以了解一下2022-04-04C語(yǔ)言進(jìn)階二叉樹的基礎(chǔ)與銷毀及層序遍歷詳解
朋友們好,這篇播客我們繼續(xù)C++的初階學(xué)習(xí),現(xiàn)在對(duì)我們對(duì)C++的二叉樹基礎(chǔ)oj與二叉樹銷毀和層序遍歷進(jìn)行練習(xí),讓我們相互學(xué)習(xí),共同進(jìn)步2022-06-06windows系統(tǒng)下C++調(diào)用matlab程序的方法詳解
這篇文章主要給大家介紹了關(guān)于在windows系統(tǒng)下C++調(diào)用matlab程序的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08C語(yǔ)言中typedef的用法以及#define區(qū)別詳解
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中typedef用法以及#define區(qū)別的相關(guān)資料,typedef 是用來(lái)定義一種類型的新別名的,它不同于宏(#define),不是簡(jiǎn)單的字符串替換。而#define只是簡(jiǎn)單的字符串替換(原地?cái)U(kuò)展),需要的朋友可以參考下2021-07-07C++面向?qū)ο笳Z(yǔ)言自制多級(jí)菜單功能實(shí)現(xiàn)代碼
菜單類主要負(fù)責(zé)菜單的創(chuàng)建、修改、刪除,是包含菜單結(jié)構(gòu)組織和響應(yīng)函數(shù)的模型,用戶擁有充分的自主性,可根據(jù)需要自定義菜單顯示和響應(yīng)函數(shù),這篇文章主要介紹了C++面向?qū)ο笳Z(yǔ)言自制多級(jí)菜單,需要的朋友可以參考下2024-06-06C++實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(完整版)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06