實(shí)例講解C語言編程中的結(jié)構(gòu)體對齊
Q:關(guān)于結(jié)構(gòu)體的對齊,到底遵循什么原則?
A:首先先不討論結(jié)構(gòu)體按多少字節(jié)對齊,先看看只以1字節(jié)對齊的情況:
#include <stdio.h> #include <string.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define OFFSET(struct,member) ((char *)&((struct *)0)->member - (char *)0) #pragma pack(1) typedef struct { char sex; short score; int age; }student; int main() { PRINT_D(sizeof(student)) PRINT_D(OFFSET(student,sex)) PRINT_D(OFFSET(student,score)) PRINT_D(OFFSET(student,age)) return 0; }
輸出:
sizeof(student) is 7 OFFSET(student,sex) is 0 OFFSET(student,score) is 1 OFFSET(student,age) is 3
可以看到,如果按1字節(jié)對齊,那么結(jié)構(gòu)體內(nèi)部的成員緊密排列,sizeof(char) == 1, sizeof(short) == 2, sizeof(int) == 4.
修改上面的代碼, 去掉#pragma pack語句,代碼如下:
#include <stdio.h> #include <string.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define OFFSET(struct,member) ((char *)&((struct *)0)->member - (char *)0) typedef struct { char sex; short score; int age; }student; int main() { PRINT_D(sizeof(student)) PRINT_D(OFFSET(student,sex)) PRINT_D(OFFSET(student,score)) PRINT_D(OFFSET(student,age)) return 0; }
運(yùn)行結(jié)果:
sizeof(student) is 8 OFFSET(student,sex) is 0 OFFSET(student,score) is 2 OFFSET(student,age) is 4
此時(shí),各個(gè)成員之間就不像之前那樣緊密排列了,而是有一些縫隙。這里需要介紹下對齊原則:
此原則是在沒有#pragma pack語句作用時(shí)的原則(不同平臺(tái)可能會(huì)有不同):
原則A:struct或者union的成員,第一個(gè)成員在偏移0的位置,之后的每個(gè)成員的起始位置必須是當(dāng)前成員大小的整數(shù)倍;
原則B:如果結(jié)構(gòu)體A含有結(jié)構(gòu)體成員B,那么B的起始位置必須是B中最大元素大小整數(shù)倍地址;
原則C:結(jié)構(gòu)體的總大小,必須是內(nèi)部最大成員的整數(shù)倍;
依據(jù)上面3個(gè)原則,我們來具體分析下: sex在偏移0處,占1字節(jié);score是short類型,占2字節(jié),score必須以2的整數(shù)倍為起始位置,所以它的起始位置為2; age為int類型,大小為4字節(jié),它必須以4的整數(shù)倍為起始位置,因?yàn)榍懊嬗衧ex占1字節(jié),填充的1字節(jié)和score占2字節(jié),地址4已經(jīng)是4的整數(shù)倍,所以age的位置為4.最后,總大小為4的倍數(shù),不用繼續(xù)填充。
繼續(xù)修改上面的代碼,增加#pragma pack語句:
#include <stdio.h> #include <string.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define OFFSET(struct, member) ((char *)&((struct *)0)->member - (char *)0) #pragma pack(4) typedef struct { char sex; short score; int age; }student; int main() { PRINT_D(sizeof(student)) PRINT_D(OFFSET(student,sex)) PRINT_D(OFFSET(student,score)) PRINT_D(OFFSET(student,age)) return 0; }
運(yùn)行結(jié)果:
sizeof(student) is 8 OFFSET(student,sex) is 0 OFFSET(student,score) is 2 OFFSET(student,age) is 4
具體分析下:
有了#pragma pack(4)語句后,之前說的原則A和C就不適用了。實(shí)際對齊原則是自身對齊值(成員sizeof大小)和指定對齊值(#pragma pack指定的對齊大小)的較小者。依次原則,sex依然偏移為0, 自身對齊值為1,指定對齊值為4,所以實(shí)際對齊為1; score成員自身對齊值為2,指定對齊值為4,實(shí)際對齊為2;所以前面的sex后面將填充一個(gè)1字節(jié),然后是score的位置,它的偏移為2;age自身對齊值為4,指定對齊為4,所以實(shí)際對齊值為4;前面的sex和score正好占用4字節(jié),所以age接著存放;它的偏移為4.
Q:關(guān)于位域的問題,空域到底表示什么?
A:它表示之后的位域從新空間開始。
#include <stdio.h> #include <string.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define OFFSET(struct, member) ((char *)&((struct *)0)->member - (char *)0) typedef struct { int a : 1; int b : 3; int : 0; int d : 2; }bit_info; int main() { PRINT_D(sizeof(bit_info)) return 0; }
運(yùn)行結(jié)果:
sizeof(bit_info) is 8
bit_info中的a, b占用4個(gè)字節(jié)的前4位,到int:0; 時(shí)表示此時(shí)將填充余下所有沒有填充的位,即剛剛的4個(gè)字節(jié)的余下28位;int d:2; 將從第四個(gè)字節(jié)開始填充,又會(huì)占用4個(gè)字節(jié),所以總大小為8.
再來看下面幾個(gè)小例子
例1:
struct A{ char f1 : 3; char f2 : 4; char f3 : 5; };
a b c
A的內(nèi)存布局:111,1111 *,11111 * * *
位域類型為char,第1個(gè)字節(jié)僅能容納下f1和f2,所以f2被壓縮到第1個(gè)字節(jié)中,而f3只能從下一個(gè)字節(jié)開始。因此sizeof(A)的結(jié)果為2。
例2:
struct B{ char f1 : 3; short f2 : 4; char f3 : 5; };
由于相鄰位域類型不同,在VC6中其sizeof為6,在Dev-C++中為2。
例3:
struct C{ char f1 : 3; char f2; char f3 : 5; };
非位域字段穿插在其中,不會(huì)產(chǎn)生壓縮,在VC6和Dev-C++中得到的大小均為3。
考慮一個(gè)問題,為什么要設(shè)計(jì)內(nèi)存對齊的處理方式呢?如果體系結(jié)構(gòu)是不對齊的,成員將會(huì)一個(gè)挨一個(gè)存儲(chǔ),顯然對齊更浪費(fèi)了空間。那么為什么要使用對齊呢?體系結(jié)構(gòu)的對齊和不對齊,是在時(shí)間和空間上的一個(gè)權(quán)衡。對齊節(jié)省了時(shí)間。假設(shè)一個(gè)體系結(jié)構(gòu)的字長為w,那么它同時(shí)就假設(shè)了在這種體系結(jié)構(gòu)上對寬度為w的數(shù)據(jù)的處理最頻繁也是最重要的。它的設(shè)計(jì)也是從優(yōu)先提高對w位數(shù)據(jù)操作的效率來考慮的。有興趣的可以google一下,人家就可以跟你解釋的,一大堆的道理。
最后順便提一點(diǎn),在設(shè)計(jì)結(jié)構(gòu)體的時(shí)候,一般會(huì)尊照一個(gè)習(xí)慣,就是把占用空間小的類型排在前面,占用空間大的類型排在后面,這樣可以相對節(jié)約一些對齊空間。
上一篇:理解C++編程中的std::function函數(shù)封裝
欄 目:C語言
下一篇:C語言system 自動(dòng)關(guān)機(jī)函數(shù)代碼
本文標(biāo)題:實(shí)例講解C語言編程中的結(jié)構(gòu)體對齊
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/2357.html
您可能感興趣的文章
- 01-10貪心算法 WOODEN STICKS 實(shí)例代碼
- 01-10輸出1000以內(nèi)的素?cái)?shù)的算法(實(shí)例代碼)
- 01-10使用map實(shí)現(xiàn)單詞轉(zhuǎn)換的實(shí)例分析
- 01-10用C++實(shí)現(xiàn)一個(gè)鏈?zhǔn)綏5膶?shí)例代碼
- 01-10C語言編程時(shí)常犯十八個(gè)錯(cuò)誤小結(jié)
- 01-10C語言函數(shù)的遞歸和調(diào)用實(shí)例分析
- 01-10C++ sizeof 實(shí)例解析
- 01-10C語言 解壓華為固件的實(shí)例代碼
- 01-10VC實(shí)現(xiàn)圖片拖拽及動(dòng)畫的實(shí)例
- 01-10C語言實(shí)現(xiàn)逆波蘭式實(shí)例


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什