0x00簡介
首先要知道結構體的對齊規制
1.第一個成員在結構體變量偏移量為0的地址處
2.其他成員變量對齊到某個數字的整數倍的地址處
對齊數=編輯器默認的一個對齊數與該成員大小的較小值
vs中默認的值為8
gcc 沒有默認就是累加
3.結構體總大小為最大對齊數(每個成員變量都有一個對齊數)的整數倍
4.如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整數體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍
0x01結構體
如下代碼
#include <string.h> #include <stdio.h> struct s1 { char c1; int a; char c2; }; struct s2 { char c1; char c2; int a; }; int main() { struct s1 s1 = { 0 }; printf("%d", sizeof(s1)); struct s2 s2 = { 0 }; printf("%d", sizeof(s2)); return 0; }
s1 的偏移量大小計算就是:
從上到下
char c1;
他的字節是1 就是 1/8 取最小值 第一個就是1 此時偏移量大小就是1
int a;
他的字節是4 就是 4/8 取最小值 就是4 偏移量大小應該是4的倍數 前面1就要填充3個 就是 4 在加int 此時偏移量大小就是8
char c2;
他的字節是1 就是 1/8 取最小值 第一個就是1 由於他是最后一個完了就是結構體 此時偏移量是8+1=9 但是結構體總大小為最大對齊數(每個成員變量都有一個對齊數)的整數倍他個結構體最大對齊數是4 所以9不是4的倍數 要在填充3個 就是12個長度
s2的偏移量大小計算就是:
char c1;
他的字節是1 就是 1/8 取最小值 第一個就是1 此時偏移量大小就是1
char c2;
他的字節是1 就是 1/8 取最小值 第一個就是1 此時偏移量大小就是2
int a;
他的字節是4 就是 4/8 取最小值 就是4 偏移量大小應該是4的倍數 前面是2就要填充2個 就是 4 在加int 此時偏移量大小就是8 正好是4的倍數不用在加了
這時查看輸出結果
12 8
0x02結構體嵌套
這里我們在看一個結構體嵌套的代碼
#include <string.h> #include <stdio.h> struct s3 { double d; char c; int i; }; struct s4 { char c; struct s3 s3; double d; }; int main() { printf("%d", sizeof(struct s4)); return 0; }
先計算s3結構體的大小
double d;
他的字節是8 就是 8/8 取最小值 第一個就是8 此時偏移量大小就是8
char c;
他的字節是1 就是 1/8 取最小值 1 此時偏移量大小就是9
int i;
他的字節是4 就是 4/8 取最小值 4 前面偏移量是9 不是4的倍數要加3個 填充就是12 在加int 此時偏移量大小就是16 結構體最大對齊數是8所以要是8的倍數 正好是8的倍數不用加了
再來計算s4的結構體大小
char c;
他的字節是1 就是 1/8 取最小值 1 此時偏移量大小就是1
struct s3 s3;
他的字節是16 結構體的最大對齊數是8 只需要前面是8的倍數就行了 前面是1 要補齊7個 就是1+7+16=24
double d;
他是8個字節 就是8/8 取最小值8 前面偏移量是24 為8的倍數不用填充 直接+8 就是32 此時結構體結束 最大對齊數是8 32正好是8的倍數不用在填充
這個結構體就是32偏移量
0x03為什么要對齊?
1.平台原因:不是所有的硬件都可以在任意地址上讀數據。
2.性能原因:內存對齊就是拿空間換時間
0x04 修改默認對齊數
主要是使用#pragma這個預處理指令。 改名默認對齊數
#pragma pack(1) struct s3 { double d; char c; int i; }; #pragma pack()
這里寫1 就是和gcc一樣的計算方式了 直接就是里面變量字節相加
這里是13
如果沒用到pragma 考慮到性能 結構體變量聲明應該是 字節小到大 例如:
struct s3 { char c; char c1; char c2; int i; double d; };