實例講授C說話編程中的構造體對齊。本站提示廣大學習愛好者:(實例講授C說話編程中的構造體對齊)文章只能為提供參考,不一定能成為您想要的結果。以下是實例講授C說話編程中的構造體對齊正文
Q:關於構造體的對齊,究竟遵守甚麼准繩?
A:起首先不評論辯論構造體按若干字節對齊,先看看只以1字節對齊的情形:
#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字節對齊,那末構造體外部的成員慎密分列,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; }
運轉成果:
sizeof(student) is 8 OFFSET(student,sex) is 0 OFFSET(student,score) is 2 OFFSET(student,age) is 4
此時,各個成員之間就不像之前那樣慎密分列了,而是有一些裂縫。這裡須要引見下對齊准繩:
此准繩是在沒有#pragma pack語句感化時的准繩(分歧平台能夠會有分歧):
准繩A:struct或許union的成員,第一個成員在偏移0的地位,以後的每一個成員的肇端地位必需是以後成員年夜小的整數倍;
准繩B:假如構造體A含有構造體成員B,那末B的肇端地位必需是B中最年夜元素年夜小整數倍地址;
准繩C:構造體的總年夜小,必需是外部最年夜成員的整數倍;
根據下面3個准繩,我們來詳細剖析下: sex在偏移0處,占1字節;score是short類型,占2字節,score必需以2的整數倍為肇端地位,所以它的肇端地位為2; age為int類型,年夜小為4字節,它必需以4的整數倍為肇端地位,由於後面有sex占1字節,填充的1字節和score占2字節,地址4曾經是4的整數倍,所以age的地位為4.最初,總年夜小為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) #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; }
運轉成果:
sizeof(student) is 8 OFFSET(student,sex) is 0 OFFSET(student,score) is 2 OFFSET(student,age) is 4
詳細剖析下:
有了#pragma pack(4)語句後,之前說的准繩A和C就不實用了。現實對齊准繩是本身對齊值(成員sizeof年夜小)和指定對齊值(#pragma pack指定的對齊年夜小)的較小者。順次准繩,sex仍然偏移為0, 本身對齊值為1,指定對齊值為4,所以現實對齊為1; score成員本身對齊值為2,指定對齊值為4,現實對齊為2;所之前面的sex前面將填充一個1字節,然後是score的地位,它的偏移為2;age本身對齊值為4,指定對齊為4,所以現實對齊值為4;後面的sex和score正好占用4字節,所以age接著寄存;它的偏移為4.
Q:關於位域的成績,空域究竟表現甚麼?
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; }
運轉成果:
sizeof(bit_info) is 8
bit_info中的a, b占用4個字節的前4位,到int:0; 時表現此時將填充余下一切沒有填充的位,即方才的4個字節的余下28位;int d:2; 將從第四個字節開端填充,又會占用4個字節,所以總年夜小為8.
再來看上面幾個小例子
例1:
struct A{ char f1 : 3; char f2 : 4; char f3 : 5; };
a b c
A的內存結構:111,1111 *,11111 * * *
位域類型為char,第1個字節僅能包容下f1和f2,所以f2被緊縮到第1個字節中,而f3只能從下一個字節開端。是以sizeof(A)的成果為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; };
非位域字段交叉在個中,不會發生緊縮,在VC6和Dev-C++中獲得的年夜小均為3。
斟酌一個成績,為何要設計內存對齊的處置方法呢?假如系統構造是纰謬齊的,成員將會一個挨一個存儲,明顯對齊更糟蹋了空間。那末為何要應用對齊呢?系統構造的對齊和纰謬齊,是在時光和空間上的一個衡量。對齊節儉了時光。假定一個別系構造的字長為w,那末它同時就假定了在這類系統構造上對寬度為w的數據的處置最頻仍也是最主要的。它的設計也是從優先進步對w位數據操作的效力來斟酌的。有興致的可以谷歌一下,人家便可以跟你說明的,一年夜堆的事理。
最初趁便提一點,在設計構造體的時刻,普通會尊照一個習氣,就是把占用空間小的類型排在後面,占用空間年夜的類型排在前面,如許可以絕對勤儉一些對齊空間。