1. 程式人生 > >C語言sizeof求結構體大小問題彙總

C語言sizeof求結構體大小問題彙總

可以說一直被各類結構體大小問題所困擾,花了大半天時間查了一下資料,現在整理彙總如下。

sizeof:C語言中判斷資料型別或者表示式長度符;不是一個函式,位元組數的計算在程式編譯時進行,而不是在程式執行的過程中才計算出來。

基本資料型別的大小很好計算,我們主要看一下構造資料型別的大小,包括陣列,結構體和共用體。

1、陣列型別,計算單個元素的大小,整個陣列大小就是單個元素大小乘以元素個數。

char a[] = "abc";
char b[100] = "abc";
......
sizeof(a); // =4 , 字元陣列末尾自動新增 '\0'
sizeof(b); // =100,記憶體中預分配的大小為100 ×1

2、結構體型別,大小不是每個結構體成員的簡單相加,需要考慮到系統儲存時結構體變數地址對齊的一系列問題。

     1)結構體的大小等於結構體內最大成員大小的整數倍

     2)結構體內的成員的首地址相對於結構體首地址的偏移量是其型別大小的整數倍,比如說double型成員相對於結構體的首地址的地址偏移量應該是8的倍數。
     3)為了滿足規則1和2編譯器會在結構體成員之後進行位元組填充!

struct{
       int a;
       static int b;
}Q;
sizeof(Q); // Q=4, 靜態變數是存放在全域性資料區的,而sizeof計算棧中分配的大小,是不會計算在內的。


tips: 32位系統,int 大小為4,char大小為1,float大小為4,double大小為8。

3、結構體中包含結構體的情況

一個完整的測試程式如下:

struct test_st1{  
    char a;  
    long b;  
};  
  
struct test_st2{  
    char c;  
    struct test_st1 st1;  
    long long d;  
};  
  
int main() {  
    struct test_st2 t;  
    int x1 = (unsigned int)(void*)&t.c - (unsigned int)(void*)&t;  
    int x2 = (unsigned int)(void*)&t.st1.a - (unsigned int)(void*)&t;  
    int x3 = (unsigned int)(void*)&t.st1.b - (unsigned int)(void*)&t;  
    int x4 = (unsigned int)(void*)&t.d - (unsigned int)(void*)&t;  
    printf("a=0x%p,b=0x%p,c=0x%p,d=0x%p", x1, x2, x3, x4);  
   system("pause");
}  
主要來看一下結構體test_st2這個結構體,c是本身是一個位元組,所以對齊方式是1,而st1是一個結構,那麼這個結構本身在其他結構體中,對齊的方式是什麼呢,是以結構體的大小和給定的對齊方式做比較嗎?不對,它的對齊方式是它成員變數中最大的那個成員變數所佔的記憶體空間和給定的值進行比較,繼而,st1的對齊方式是4,它的起始地址是可以整除4的地方開始。 對於d,因為它佔用8個位元組的記憶體,所以它的對齊方式是8,c和st1用去了12個位元組,所以d從記憶體地址可以整除8的地方開始存放,所以這個test_st2結構體的大小是24。測試結果如圖:




4、幾個常見面試題

    a). sizeof在計算變數所佔空間大小時採取的機制;

       結構體的大小等於結構體內最大成員大小的整數倍;結構體內的成員的首地址相對於結構體首地址的偏移量是其型別大小的整數倍,比如說double型成員相對於結構體的首地址的地址偏移量應該是8的倍數。

    b).如果是自己為一個類寫一個sizeof函式,應該考慮哪些問題

方式一:

#define SIZEOF(X) (int)((X)+1) - (int)(X)

char a[2]; //定義一個同類型的陣列,兩個元素的地址差就是該型別資料所佔位元組數
printf("%d", SIZEOF(a));  //這裡的可以求任意資料型別的所佔的位元組數。

方式二:

#define my_sizeof(L_Value)  (char* )(&L_Value + 1) - (char* ) (&L_Value)

int main(void)
{    
     char a; 
     printf("%d", my_sizeof(a));
     system("pause");
}     

  c).虛擬函式和虛繼承對於一個類求sizeof的影響有什麼差別

class A {
       public:
             virtual void funa();
             virtual void funb();
             void func();
             static void fund();
             static int si;
       private:
             int i;
             char c;
};


問:sizeof(A) = ?
解答:
關於類佔用的記憶體空間,有以下幾點需要注意:
(1)如果類中含有虛擬函式,則編譯器需要為類構建虛擬函式表,類中需要儲存一個指標指向這個虛擬函式表的首地址,注意不管有幾個虛擬函式,都只建立一張表,所有的虛擬函式地址都存在這張表裡,類中只需要一個指標指向虛擬函式表首地址即可。
(2)類中的靜態成員是被類所有例項所共享的,它不計入sizeof計算的空間
(3)類中的普通函式或靜態普通函式都儲存在棧中,不計入sizeof計算的空間
(4)類成員採用位元組對齊的方式分配空間

答案:12(32位系統)或16(64位系統)