天天看點

淺說c/c++的sizeof

1 初識sizeof,sizeof的定義

sizeof是c/c++中的一個操作符,用于傳回一個對象或者類型所占用的記憶體位元組數。sizeof傳回值的類型為為size_t,一般在頭檔案中定義為 typedef unsigned int size_t。sizeof傳回值的大小依賴于編譯系統,下面我們要讨論的都是限定在32位編譯系統下的。

2.小試牛刀,sizeof的使用方法

2.1 用于資料類型,如:

2.2 用于對象,如:

int number = ; 

sizeof(number); // OK

sizeof number; // OK
           

PS:對于類型來說,必須用()包住,如:

是以為了統一,在一般情況下,即使是對于對象,我們也用()包住。實際上,sizeof計算單個對象的大小也是轉換成對象類型的計算 。需要注意的是,sizeof 操作符不能作用于函數,不完全類型或位字段(bit-field)。如 :

int test1()
 {
      int number = ;

      return number;
 }

 void test2()
 {
       //do nothing
 }

 sizeof( test1 );//ERROR

 sizeof( test2() );//ERROR

 sizeof( test2 );//ERROR
           

還有一點sizeof也可以作用于函數調用的,其結果是函數傳回類型(不能為void)的大小,而且函數并不會實際地調用,可以參考下圖。

淺說c/c++的sizeof

3.庖丁解牛,深入了解sizeof

3.1 sizeof的常量性

sizeof的計算發生在編譯期間,是以它可以當做常量表達式使用,如

3.2 内置類型的sizeof

内置類型包括int,unsigned int,short,double,float 等等等。這些類型的sizeof的大小依賴于編譯器的具體實作,如在32位系統,sizeof(int)大小為4位元組。特别的,對于char,unsigned char和signed char來說,标準規定了它們的sizeof大小就是為1位元組。

3.3 指針變量的sizeof

對于指針變量的sizeof大小同樣依賴于編譯器的實作,一般來說在32位系統下,指針變量的sizeof大小為4位元組。

3.4 數組的sizeof

數組的sizeof大小等于數組内各個元素占用的位元組數之和。如下圖所示:對arr數組做sizeof操作得到的值為16位元組。

淺說c/c++的sizeof

利用這個特性,我們很容易用memset函數來初始化數組了。memset函數的原型為:

void* memset(void *s,int ch,size_t n);
           

其作用就是将s中目前位置後面的 n 個位元組用 ch 替換并傳回 s 。 是以對于數組來說,我們很自然的就可以用 memset(arr,0,sizeof(arr));這樣的形式來初始化數組了。

3.5 結構體/類的sizeof

對于結構體或類的sizeof大小,是比較容易犯錯也是在面試中經常被考察的一部分。下面我們來具體分析下。

3.5.1 空類的sizeof

1)對于

class CTest{};sizeof( CTest);

為多少呢?理論上,沒有資料成員的類的大小應該為0,但是實際上sizeof(CTest)的大小卻為1,這是為什麼呢?先了解一個概念:類的執行個體化,所謂類的執行個體化就是在記憶體中配置設定一塊位址,每個執行個體在記憶體中都有獨一無二的位址。同樣空類也會被執行個體化,是以編譯器會給空類隐含的添加一個位元組,這樣空類執行個體化之後就有了獨一無二的位址了。是以空類的sizeof為1。

2)對于基類和子類都是空類的情況下,子類的sizeof大小為多少呢?會是2麼?看如下的代碼。

淺說c/c++的sizeof

很明顯,對于了繼承了空類的子類sizeof大小同樣為1。

3.5.2 有虛函數類的sizeof
class CTest
{
    public:
    virtual ~CTest();
};
           

sizeof(CTest)的大小會是多少呢?會是1麼?看看執行的結果:

淺說c/c++的sizeof

結果是4位元組,為什麼呢?這是因為一般來說編譯器會為包含了虛函數的類建立一個表(VTABLE),并且還秘密的在類中放置一個指針(VPTR),來指向這個表。指針變量的sizeof大小是多少呢?通過前面我們知道,在32位編譯系統下是4,符合我們的預期。

3.5.3 帶有靜态資料成員的類
class CTest
{
    int data;
    static int value;
};
           

同樣我們會好奇sizeof(CTest)的大小為多少呢?看看下面代碼執行的結果。

淺說c/c++的sizeof

在類裡面,靜态的資料成員雖然屬于這個類,但是卻不影響這個類的大小。是以,CTest類的sizeof大小就是sizeof(int)的大小,為4位元組。

3.5.4 考慮到記憶體對齊的sizeof
class CTest
{
    char ch;
    int  data;
};
           

從直覺上看,sizeof(CTest)的大小為sizeof(char)+sizeof(int)的大小也就是5個位元組,然而真的是麼?看看如下代碼執行的結果:

淺說c/c++的sizeof

為什麼是8個位元組呢?這就要考慮到記憶體對齊方式了。關于記憶體對齊方式我們在這裡不做過多介紹,有興趣的讀者可以自行查閱别的資料。在這裡我們隻考慮到編譯器預設(不考慮#pragma pack)的記憶體對齊方式,sizeof的結果請牢記以下3條原則:

1:資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第一個資料成員放在offset為0的地方,以後每個資料成員存儲的起始位置要從該成員大小或者成員的子成員大小(隻要該成員有子成員,比如說是數組,結構體等)的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍位址開始存儲)。

2:結構體作為成員:如果一個結構裡有某些結構體成員,則結構體成員要從其内部最大元素大小的整數倍位址開始存儲.(struct a裡存有struct b,b裡有char,int ,double等元素,那b應該從8的整數倍開始存儲.)

3:收尾工作:結構體的總大小,也就是sizeof的結果,.必須是其内部最大成員的整數倍.不足的要補齊.

總結: 在這裡我們考慮多種情況下sizeof的結果,當然還有一些情況沒有讨論,包括但不限于:1)通過 #pragma pack改變記憶體對齊方式 ;2)union類型的sizeof大小;3)含位域結構體的sizeof等等。這些情況讀者可以自行去查閱相關資料。

PS: 筆者學識有限,行文或對c++了解難免會有錯誤,若有不對處,還請各位指正。

參考資料:

http://blog.csdn.net/wzy198852/article/details/7246836

http://blog.csdn.net/zzhongcy/article/details/38361755

http://www.360doc.com/content/11/0324/15/6637130_104204413.shtml

繼續閱讀