C/C++中結構體佔用記憶體大小的計算方法
引言
結構體在C語言中雖然經常使用,但是怎麼計算一個結構體佔用多大的記憶體,很多C語言的新手都沒注意過,其實C語言的語法簡單,難就難在它更偏向於與底層,與記憶體打交道。對於嵌入式方面來說,對C語言的要求更高,因為有些硬體的記憶體並不像我們使用的電腦的記憶體那麼充裕,所以需要節約記憶體。
結構體中同樣的變數個數,卻可能導致佔用記憶體的大小不同。
例子1:
輸出的結果為:32#include <stdio.h> int main() { typedef struct a { int c; double d; char b[10]; }test; test e; printf("%d", sizeof(test)); return 0; }
例子2:
#include <stdio.h>
int main()
{
typedef struct a
{
double d;
int c;
char b[10];
}test;
test e;
printf("%d", sizeof(test));
return 0;
}
輸出的結果為:24
只是調換了一下int c和double d的位置,就導致了前者比後者多佔用了8個位元組的記憶體。這只是一個小例子。那麼,結構體中到底怎麼計算記憶體的呢。
計算規則
首先需要介紹<b>有效對齊值</b>:每個平臺上的編譯器都有預設對齊係數n,可以通過#pragma pack(n)來指定。有效對齊值就等與該對齊係數和結構體中最長的資料型別的長度兩者最小的那一個值,比如對齊係數是8,而結構體中最長的是int,4個位元組,那麼有效對齊值為4。
結構體的記憶體計算方式遵循以下規則:
1.資料成員對齊規則:第一個資料成員放在offset為0的地方,以後的每一個成員的offset都必須是該成員的大小與有效對齊值相比較小的數值的整數倍,例子1中第一個資料成員是int 型,第二個是double,有效對齊值為8,所以double的起始地址應該為8,所以第一個int加上記憶體補齊用了8個位元組
2.結構體作為成員:如果一個結構裡有某些結構體成員,則結構體成員要從其內部有效對齊值的整數倍地址開始儲存。(比如struct a中存有struct b,b裡有char, int, double,那b應該從8的整數倍開始儲存)
3.收尾工作:結構體的總大小,必須是其有效對齊值的整數倍,不足的要補齊。
有了這些規則,再來看上面的兩個例子。
例子1中,int為第一個資料成員,所以下一個儲存的起始位置是4,但是double佔8個位元組,按規則一,不滿足8的倍數,填充到16,char一共有10個位元組(陣列在記憶體中的表示會分解成單個的),即總共26,進行收尾工作,有效對齊值為8,26不滿足8的倍數,填充到32。
例子2中,double為第一個資料成員,所以下一個儲存的起始位置是8,按規則一,佔用了12個位元組,char有10個位元組,一共用了22個位元組,進行收尾工作,該結構體中有效對齊值為8,22不滿足8的倍數,填充到24。
例子
下面給你一個question,考察你是否懂了上面的規則
#include <stdio.h>
#pragma pack(8)
int main()
{
struct Test
{
int a;
//long double大小為16bytes
long double b;
char c[10];
};
printf("%d", sizeof(Test));
return 0;
}
#include <stdio.h>
#pragma pack(16)
int main()
{
struct Test
{
int a;
//long double大小為16bytes
long double b;
char c[10];
}
printf("%d", sizeof(Test));
return 0;
}
如果你計算得出的答案分別為40和48,那我相信你就懂了記憶體對齊的奧祕了。