原文鏈接:sizeof()計算結構體的大小_海月汐辰-CSDN博客_結構體的sizeof怎么計算
簡要說明:結構體成員按照定義時的順序依次存儲在連續的內存空間,但是結構體的大小并不是簡單的把所有成員大小相加,而是遵循一定的規則,需要考慮到系統在存儲結構體變量時的地址對齊問題。
一、沒有成員的結構體占用的空間是多少個字節?
? ? ?答案是:1個字節。
? ? ?這就是實例化的原因(空類同樣可以被實例化),每個實例在內存中都有一個獨一無二的地址,為了達到這個目的,編譯器往往會給一個空類或空結構體(C++中結構體也可看為類)隱含的加一個字節,這樣空類或空結構體在實例化后在內存得到了獨一無二的地址,所以空類所占的內存大小是1個字節。
二、首先介紹一個相關的概念——偏移量
? ? ? ? ? struct stru?
? ? ? ? ?{ ?
? ? ? ? ? ? ? ? ? ? int a; ?//start address is 0
? ? ? ? ? ? ? ? ? ?char b; ?//start address is 4
? ? ? ? ? ? ? ? ? ?int c; ?//start address is 8
? ? ? ? ?};
? ? ? ? ?偏移量指的是結構體變量中成員的地址和結構體變量地址的差。結構體大小等于最后一個成員的偏移量加上最后一個成員的大小。顯然,結構體變量中第一個成員的地址就是結構體變量的首地址。比如上面的結構體,第一個成員a的偏移量為0。第二個成員b的偏移量是第一個成員的偏移量加上第一個成員的大小(0+4),其值為4;第三個成員c的偏移量是第二個成員的偏移量應該是加上第二個成員的大小(4+1)。
三、在實際中,存儲變量時地址要求對齊,編譯器在編譯程序時會遵循兩條原則:
? ? ? ? ? ? ?(1)結構體變量中成員的偏移量必須是成員大小的整數倍(0被認為是任何數的整數倍)?
? ? ?(2)結構體大小必須是所有成員大小的整數倍,也即所有成員大小的公倍數。
例子1:
struct stru1 ?
{ ?
? ? ?int a; ?//start address is 0
? ? ?char b; ?//start address is 4
? ? ?int c; ?//start address is 8
};
PS:用sizeof求該結構體的大小,發現值為12。int占4個字節,char占1個字節,結果應該是9個字節才對啊,為什么呢?這個例子中前兩個成員的偏移量都滿足要求,但第三個成員的偏移量為5,并不是自身(int)大小的整數倍。編譯器在處理時會在第二個成員后面補上3個空字節,使得第三個成員的偏移量變成8。結構體大小等于最后一個成員的偏移量加上其大小,上面的例子中計算出來的大小為12,滿足要求。
例子2:
struct stru2 ?
{ ?
? ? ? int i; ?//start address is 0
? ? ? short m; ?//start address is 4
};
PS:成員i的偏移量為0;成員m的偏移量為4,都不需要調整。但計算出來的大小為6,顯然不是成員m大小的整數倍。因此,編譯器會在成員m后面補上2個字節,使得結構體的大小變成8從而滿足第二個要求。
例子3、4:
?struct stru3 ?
{ ??
? ? ? ?char i; ?//start address is 0?
? ? ? ?int m; ? //start address is 4
? ? ? ?char n; ?//start address is 8
}; ?
struct stru4 ?
{ ?
? ? ? ?char i; ?//start address is 0
? ? ? ?char n; ?//start address is 1
? ? ? ?int m; ?//start address is 4
?};?
雖然結構體stru3和stru4中成員都一樣,但sizeof(struct stru3)的值為12而sizeof(struct stru4)的值為8。
由此可見,結構體類型需要考慮到字節對齊的情況,不同的順序會影響結構體的大小。
四、 對于嵌套的結構體,需要將其展開。對結構體求sizeof時,上述兩種原則變為:
? ? ? ?(1)展開后的結構體的第一個成員的偏移量應當是被展開的結構體中最大的成員的整數倍。
? ? ? ?(2)結構體大小必須是所有成員大小的整數倍,這里所有成員計算的是展開后的成員,而不是將嵌套的結構體當做一個整體。
例子1:
struct stru5 ?
{ ?
? ? ? short i; ?
? ? ? struct ??
? ? ? { ?
? ? ? ? ? ?char c; ?
? ? ? ? ? ?int j; ?
? ? ? } tt; ??
? ? ? int k; ?
};
結構體stru5的成員tt.c的偏移量應該是4,而不是2。整個結構體大小應該是16。
例子2:
struct stru6 ?
{ ?
? ? ? char i; ?
? ? ? struct ??
? ? ? { ?
? ? ? ? ? ?char c; ?
? ? ? ? ? ?int j; ?
? ? ? } tt; ??
? ? ? char a; ?
? ? ? char b; ?
? ? ? char d; ?
? ? ? char e; ?
? ? ? int f; ?
};
結構體tt單獨計算占用空間為8,而stru6的sizeof則是20,不是8的整數倍,這說明在計算sizeof(stru6)時,將嵌套的結構體ss展開了,這樣stu6中最大的成員為tt.j,占用4個字節,20為4的整數倍。如果將tt當做一個整體,結果應該是24了。
五:另一個特殊的例子是結構體中包含數組,其sizeof應當和處理嵌套結構體一樣,將其展開,如下例子:
struct array ?
{ ?
? ? float f; ?
? ? char p; ?
? ? int ?arr[3]; ?
};
其值為20。float占4個字節,到char p時偏移量為4,p占一個字節,到int arr[3]時偏移量為5,擴展為int的整數倍,而非int arr[3]的整數倍,這樣偏移量變為8,而不是12。結果是8+12=20,是最大成員float或int的大小的整數倍。
測試環境:vc++6.0
測試代碼:
?
//#ifndef __cplusplus//#endif#include <iostream>
#include "stdio.h"
#include <stdlib.h>
using namespace std;struct stru_empty
{};
struct stru1
{ int a; //start address is 0char b; //start address is 4int c; //start address is 8
};
struct stru2
{ int i; //start address is 0short m; //start address is 4
};
struct stru3
{ char i; //start address is 0 int m; //start address is 4char n; //start address is 8
};
struct stru4
{ char i; //start address is 0char n; //start address is 1int m; //start address is 4};struct stru5
{ short i; struct { char c; int j; } ss; int k;
};
struct stru6
{ char i; struct { char c; int j; } tt; char a; char b; char d; char e; int f;
};
struct stru7
{ char i; struct { char c; //int j; } tt; char a; char b; char d; char e; int f;
};
struct array
{ float f; char p; int arr[3];
};
int main()
{ struct stru6 st6;struct stru7 st7;struct array ar;printf("sizof(char)=%d \n",sizeof(char));printf("sizof(int)=%d \n",sizeof(int));printf("sizof(short int)=%d \n",sizeof(short int));printf("sizof(long int)=%d \n",sizeof(long int));printf("sizof(long)=%d \n",sizeof(long));printf("sizof(float)=%d \n\n",sizeof(float));printf("sizof(stru_empty)=%d \n",sizeof(stru_empty));printf("sizof(stru1)=%d \n\n",sizeof(stru1));printf("sizof(stru2)=%d \n\n",sizeof(stru2));printf("sizof(stru3)=%d \n\n",sizeof(stru3));printf("sizof(stru4)=%d \n\n",sizeof(stru4));printf("sizof(stru5)=%d \n\n",sizeof(stru5));printf("sizof(stru6)=%d \n",sizeof(stru6)); printf("sizof(stru6.tt)=%d \n",sizeof(st6.tt));printf("the address of stru6.i=%d \n",&st6.i);printf("the address of stru6.a=%d \n\n",&st6.a);printf("sizof(stru7)=%d \n",sizeof(stru7));printf("sizof(stru7)=%d \n",sizeof(st7.tt));printf("the address of stru7.i=%d \n",&st7.i);printf("the address of stru7.a=%d \n\n",&st7.a);printf("sizof(ar)=%d \n",sizeof(ar));printf("sizof(ar.f)=%d \n",sizeof(ar.f));printf("sizof(ar.arr)=%d \n",sizeof(ar.arr));return 0;
}
運行結果:
?