日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言-结构体内存对齐

發(fā)布時間:2023/11/30 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言-结构体内存对齐 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

C語言結(jié)構(gòu)體對齊也是老生常談的話題了。基本上是面試題的必考題。內(nèi)容雖然很基礎(chǔ),但一不小心就會弄錯。寫出一個struct,然后sizeof,你會不會經(jīng)常對結(jié)果感到奇怪?sizeof的結(jié)果往往都比你聲明的變量總長度要大,這是怎么回事呢?

  開始學的時候,也被此類問題困擾很久。其實相關(guān)的文章很多,感覺說清楚的不多。結(jié)構(gòu)體到底怎樣對齊?

  有人給對齊原則做過總結(jié),具體在哪里看到現(xiàn)在已記不起來,這里引用一下前人的經(jīng)驗(在沒有#pragma pack宏的情況下):

  原則1、數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)(struct或聯(lián)合union)的數(shù)據(jù)成員,第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)成員存儲的起始位置要從該成員大小的整數(shù)倍開始(比如int在32位機為4字節(jié),則要從4的整數(shù)倍地址開始存儲)。

  原則2、結(jié)構(gòu)體作為成員:如果一個結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲。(struct a里存有struct b,b里有char,int,double等元素,那b應(yīng)該從8的整數(shù)倍開始存儲。)

  原則3、收尾工作:結(jié)構(gòu)體的總大小,也就是sizeof的結(jié)果,必須是其內(nèi)部最大成員的整數(shù)倍,不足的要補齊。

  這三個原則具體怎樣理解呢?我們看下面幾個例子,通過實例來加深理解。

????例1:

struct {short a1;short a2;short a3; } A;struct{long a1;short a2; } B;

????????? sizeof(A) = 6; 這個很好理解,三個short都為2。

????????? sizeof(B) = 8; 這個比是不是比預(yù)想的大2個字節(jié)?long為4,short為2,整個為8,因為原則3。

????例2:

struct A{int a;char b;short c; };struct B{char b;int a;short c; };

???????sizeof(A) = 8; int為4,char為1,short為2,這里用到了原則1和原則3。

?????? sizeof(B) = 12; 是否超出預(yù)想范圍?char為1,int為4,short為2,怎么會是12?還是原則1和原則3。

???深究一下,為什么是這樣,我們可以看看內(nèi)存里的布局情況。

?????????????????a???????? b???????? c
???A的內(nèi)存布局:1111,???? 1*,?????? 11

?????????????????b????????? a??????? c
???B的內(nèi)存布局:1***,???? 1111,?? 11**

???其中星號*表示填充的字節(jié)。A中,b后面為何要補充一個字節(jié)?因為c為short,其起始位置要為2的倍數(shù),就是原則1。c的后面沒有補充,因為b和c正好占用4個字節(jié),整個A占用空間為4的倍數(shù),也就是最大成員int類型的倍數(shù),所以不用補充。

???B中,b是char為1,b后面補充了3個字節(jié),因為a是int為4,根據(jù)原則1,起始位置要為4的倍數(shù),所以b后面要補充3個字節(jié)。c后面補充兩個字節(jié),根據(jù)原則3,整個B占用空間要為4的倍數(shù),c后面不補充,整個B的空間為10,不符,所以要補充2個字節(jié)。

???再看一個結(jié)構(gòu)中含有結(jié)構(gòu)成員的例子:

?????? 例3:

struct A{int a;double b;float c; };struct B{char e[2];int f;double g;short h;struct A i; };

?????? sizeof(A) = 24; 這個比較好理解,int為4,double為8,float為4,總長為8的倍數(shù),補齊,所以整個A為24。

?????? sizeof(B) = 48; 看看B的內(nèi)存布局。

???????????????????????????????? e???????? f???????????? g??????????????? h??????????????????????????????????? i?
????B的內(nèi)存布局:11* *,?? 1111,?? 11111111, 11 * * * * * *,??????? 1111* * * *, 11111111, 1111 * * * *

????i其實就是A的內(nèi)存布局。i的起始位置要為24的倍數(shù),所以h后面要補齊。把B的內(nèi)存布局弄清楚,有關(guān)結(jié)構(gòu)體的對齊方式基本就算掌握了。

????以上講的都是沒有#pragma pack宏的情況,如果有#pragma pack宏,對齊方式按照宏的定義來。比如上面的結(jié)構(gòu)體前加#pragma pack(1),內(nèi)存的布局就會完全改變。sizeof(A) = 16; sizeof(B) = 32;

????有了#pragma pack(1),內(nèi)存不會再遵循原則1和原則3了,按1字節(jié)對齊。沒錯,這不是理想中的沒有內(nèi)存對齊的世界嗎。

????????????????????????????????? a??????????????? b???????????? c
?????? A的內(nèi)存布局:1111,???? 11111111,?? 1111

???????????????????????????????? e??????? f???????????? g????????? h???????????????????? i
?????? B的內(nèi)存布局:11,?? 1111,?? 11111111, 11 ,??????????? 1111, 11111111, 1111

?????? 那#pragma pack(2)的結(jié)果又是多少呢?#pragma pack(4)呢?留給大家自己思考吧,相信沒有問題。

?????? 還有一種常見的情況,結(jié)構(gòu)體中含位域字段。位域成員不能單獨被取sizeof值。C99規(guī)定int、unsigned int和bool可以作為位域類型,但編譯器幾乎都對此作了擴展,允許其它類型類型的存在。

?????? 使用位域的主要目的是壓縮存儲,其大致規(guī)則為:
?????? 1) 如果相鄰位域字段的類型相同,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止;
?????? 2) 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數(shù)倍;
?????? 3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實現(xiàn)有差異,VC6采取不壓縮方式,Dev-C++采取壓縮方式;
?????? 4) 如果位域字段之間穿插著非位域字段,則不進行壓縮;
?????? 5) 整個結(jié)構(gòu)體的總大小為最寬基本類型成員大小的整數(shù)倍。

??????? 還是讓我們來看看例子。

?????? 例4:

struct A{char f1 : 3;char f2 : 4;char f3 : 5; };

???????????????????? a????????b???????????? c
?????? A的內(nèi)存布局:111,??? 1111 *,?? 11111 * * *

?????? 位域類型為char,第1個字節(jié)僅能容納下f1和f2,所以f2被壓縮到第1個字節(jié)中,而f3只能從下一個字節(jié)開始。因此sizeof(A)的結(jié)果為2。

?????? 例5:

struct B{char f1 : 3;short f2 : 4;char f3 : 5; };

?????? 由于相鄰位域類型不同,在VC6中其sizeof為6,在Dev-C++中為2。

?????? 例6:

struct C{char f1 : 3;char f2;char f3 : 5; };

?????? 非位域字段穿插在其中,不會產(chǎn)生壓縮,在VC6和Dev-C++中得到的大小均為3。

?????? 考慮一個問題,為什么要設(shè)計內(nèi)存對齊的處理方式呢?如果體系結(jié)構(gòu)是不對齊的,成員將會一個挨一個存儲,顯然對齊更浪費了空間。那么為什么要使用對齊呢?體 系結(jié)構(gòu)的對齊和不對齊,是在時間和空間上的一個權(quán)衡。對齊節(jié)省了時間。假設(shè)一個體系結(jié)構(gòu)的字長為w,那么它同時就假設(shè)了在這種體系結(jié)構(gòu)上對寬度為w的數(shù)據(jù) 的處理最頻繁也是最重要的。它的設(shè)計也是從優(yōu)先提高對w位數(shù)據(jù)操作的效率來考慮的。有興趣的可以google一下,人家就可以跟你解釋的,一大堆的道理。

?????? 最后順便提一點,在設(shè)計結(jié)構(gòu)體的時候,一般會尊照一個習慣,就是把占用空間小的類型排在前面,占用空間大的類型排在后面,這樣可以相對節(jié)約一些對齊空間。

轉(zhuǎn)載于:https://www.cnblogs.com/JohnABC/p/4704789.html

總結(jié)

以上是生活随笔為你收集整理的C语言-结构体内存对齐的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。