關鍵字之sizeof

sizeof哭着說:“你真的瞭解我嗎?”。。。
對於sizeof這個關鍵字,其實我猜大家都知道一點,因爲c語言初期就會接觸到它,但是又瞭解的不是很透徹,對於基本數據類型,指針,數組,結構體,函數,聯合體,類,位域成員,位域結構體等的字節計算能搞清楚嗎?沒事,往下看。
一.定義
首先:sizeof運算符的類型爲size_t(size_t在頭文件stddef.h中定義),它依賴於編譯系統的值,此運算符使您可以避免指定設備相關的數據範圍在程序。
其次:它的作用是範圍一個對象或類型所佔的內存字節。
最後:明確一點sizeof是一個操作符,不是一個函數。(衆所周知,函數後面必須要有括號裏面是形參,用於我們調用函數,但sizeof的括號可以省略,所以恰恰證明了sizeof並不是一個函數。)
這裏寫圖片描述
(對啦,說一下,我加的stdlib.h頭文件和system(“pause”)是爲了把輸出框留住,你們不用加哦,yeahyeah)
二.語法
sizeof有三種語法形式:

1) sizeof (object); //sizeof (對象)

2) sizeof object; //sizeof 對象

3) sizeof (type_name); //sizeof (類型)

對象可以是各種類型的變量,以及表達式。
我們一般習慣於第一種,第三種形式,雖然第二種形式是正確的,但是不常使用,所以我們一般見到的sizeof都是帶括號的,也因此很多同學誤以爲sizeof是個函數(error)。
三.基本數據類型的sizeof
對於基本數據類型的sizeof運算,大家看到下面的圖應該就明白了。(我的系統是32位,64位下long的8字節)
這裏寫圖片描述
四.表達式的sizeof
對於表達式的sizeof運算我們先拋出一個問題,大家可以先想想。

#include<iostream>
#include<stdlib.h>
using namespace std;

int main()
{
    int a = 10;
    cout<<sizeof (a++)<<endl;
    cout<<sizeof (++a)<<endl;
    system("pause");
    return 0;
}

你有結果了嗎?
好啦!答案揭曉:兩個輸出結果都是4.可是爲什麼呢?
我們來看看反彙編代碼吧
這裏寫圖片描述
大家可以看到我紅色圈出的部分,果然傳參的時候是直接push了4,而a++這個指令在沒有在彙編中出現的痕跡。
但是sizeof操作符並不像#define這樣的宏一樣在預處理階段就把其替換掉了,sizeof是在編譯階段替換的。(同理++a是一樣的,大家下去可以驗證)
於是理解了,sizeof裏面的表達式都是不執行的,只關心裏面類型的大小。
五.指針類型的sizeof
大家都知道指針是一個很複雜,很重要的部分,但是指針對於sizeof運算卻是非常的簡單,大家只要記住32位下不管什麼類型的指針在內存中只佔四個字節,64位中佔八個字節(任何類型指針哦)。
六.數組的sizeof
數組的sizeof值等於數組所佔用的內存字節數。
我們來看一個問題:

#include<iostream>
#include<stdlib.h>
using namespace std;

void func(char a[])
{
    int c = sizeof( a );
    cout<<c<<endl;
}
int main()
{
    char a[3];
    int array[3];
    char ptr1[] = "hallo";
    char *ptr2 = "hallo";
    cout<<sizeof (ptr1)<<endl;  //6
    cout<<sizeof (ptr1[2])<<endl;  //1
    cout<<sizeof (ptr2)<<endl;  //4
    cout<<sizeof (array)<<endl;  //12
    cout<<sizeof (array[2])<<endl;  //4
    func(a);  //4
    system("pause");
    return 0;
}

按順序:第一個輸出爲6,因爲是char類型,大家有疑問hello是五個字節嗎?對啦,還有一個終止符,即“\0”。第二個輸出爲1,因爲ptr1這個數組一共有五個元素,ptr1[2]則指第三個元素佔幾個字節,由char類型可知爲一個字節。第三個輸出爲4,因爲ptr2是個數組指針,前面我們說過,不管什麼類型指針在32位系統下都是四個字節。第四個輸出爲12,因爲數組名代表整個數組,數組的sizeof值等於數組所佔用的內存字節數,所以3*4=12.第五個輸出爲4,和第二個相似,只取決於類型,因爲是int,所以輸出四個字節。第六個輸出爲4,因爲形參中的數組退化爲一個char*的指針,所以我們就等於在對一個指針求sizeof,當然是4啦。
數組的長度的計算公式:
Int len = sizeof(arr)/ sizeof( arr[ 0 ] );
七.結構體的sizeof
sizeof在結構體部分的運算應該是最讓初學者頭疼的問題,那麼我們依然來看一個簡單的例子:
這裏寫圖片描述
怎麼樣?是不是很自信的覺得是5,nonono..那只是你覺得,對於8這個結果,那我們就必須提一下結構體內存字節對齊原則啦!
結構體內存對齊原則:
關於結構體內存對齊(在沒有#pragma pack宏的情況下) :
•原則1
數據成員對齊規則:結構(struct或聯合union)的數據成員,第一個數據成員放在offset爲0的地方,以後每個數據成員存儲的起始位置要從該成員大小的整數倍開始(比如int在32位機爲4字節,則要從4的整數倍地址開始存儲)。
看到這個規則,你們是不是想如果int和char倒一下位置是不就好啦,那我們來試一下。
no~真相又再一次不像你以爲的那樣。所以,繼續往下看吧。
•原則2
結構體作爲成員:如果一個結構裏有某些結構體成員,則結構體成員要從其內部最大元素數據類型的字節大小的整數倍地址開始存儲。(struct a裏存有struct b,b裏有char,int,double等元素,那b應該從8的整數倍開始存儲。)
第二個原則看完明白了吧,並不是倒一下兩個類型就可以完成的,人家在意的是這些類型中佔內存最大的哪一個啦。。。
•原則3
也就是說, 結構體的總大小,也就是sizeof的結果,必須是其內部最大成員的整數倍,不足的要補齊。

八.聯合體的sizeof
聯合體在內存中是重疊式,也就是說它的內存是最大數據類型所佔的字節。
這裏寫圖片描述
所以這裏整個聯合體所佔的字節數就是最大的數據類型double所佔的字節數,爲8
利用union的特性來判斷大小端:

#include<iostream>
using namespace std;

union U
{
    int a;
    char b;
}u;
int main()
{
    U u;
    u.b = 1;
    if(u.a == 1)
    {
        cout<<"小端"<<endl;
    }
    else
        cout<<"大端"<<endl;
    return 0;
}

首先我們瞭解一下聯合體的特徵:在union中所有的成員共用同一個空間,同一時間只存儲一個數據成員,最大的特徵就是所有的數據成員具有相同的起始地址即聯合體的基地址。

計算機中字節存儲主要有兩種:大端模式和小端模式,大端模式是從低地址開始,高位結束;小端模式是從高地址開始,低地址結束。

利用union中所有數據成員具有同樣的起始地址的特點,通過一個int成員存儲1,然後通過char成員來讀取,即可巧妙地得出數據存放的方式,若通過char成員(即讀取起始位置上的第一個字節)讀取,若得出值爲1,則說明是小端模式。
九函數的sizeof
sizeof可以對函數調用取值,結果爲返回值的字節大小,但是函數本身並不會被調用。因爲函數的sizeof結果爲返回值的字節,所以在Windows下返回值爲void的函數取sizeof會報錯。

#include<iostream>
using namespace std;

void fun()
{
}
int fun1(int a,int b)
{
    return a+b;
}
int main()
{
    int a = 1;
    int b = 2;
    //cout<<sizeof(fun())<<endl;
    cout<<sizeof(fun1(a,b))<<endl;
    return 0;
}

而在gcc中,返回值爲void的可以編譯成功,結果爲1,大家可以自己試試。
十.類的sizeof
在C++ 中struct 和class都是類,它們的唯一區別就是strcut 是默認公有(public)限定,class默認私有(private)限定。還有,我們應該清楚的是在c++中空struct和空class的大小都爲1字節。
這裏寫圖片描述
在虛函數和純虛函數中,會產生一個指向虛函數表的指針(vfptr),所以字節數要加上指針四個字節。只有一個虛函數或純虛函數的類有四個字節。
這裏寫圖片描述
在繼承中,如果B繼承了A,那麼B也會繼承A裏所有的成員變量,加上自己的成員變量的字節數就是B的內存大小。
如下圖:
沒有繼承關係:
這裏寫圖片描述
有繼承關係:
這裏寫圖片描述

發佈了26 篇原創文章 · 獲贊 34 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章