C++中的sizeof函數

C++中的sizeof()函數我們常常會見到,但是更多的是隻是熟悉,而並沒有真正的瞭解過,下面就對這個函數做一個深入的介紹。
sizeof是C/C++中的一個操作符(operator),其作用就是返回一個對象或者類型所佔的內存字節數。
其返回值類型爲size_t。(size_t在頭文件stddef.h中定義,它依賴於編譯系統的值,一般定義爲 typedef unsigned int size_t;)
用法:
sizeof有三種語法形式:
1) sizeof (object); //sizeof (對象)
2) sizeof object; //sizeof 對象
3) sizeof (type_name); //sizeof (類型)
對象可以是各種類型的變量,以及表達式(一般sizeof不會對表達式進行計算)。
sizeof對對象求內存大小,最終都是轉換爲對對象的數據類型進行求值。
sizeof (表達式); //值爲表達式的最終結果的數據類型的大小

int i;  
sizeof(int); //值爲4  
sizeof(i); //值爲4,等價於sizeof(int)  
sizeof i; //值爲4  
sizeof(2); //值爲4,等價於sizeof(int),因爲2的類型爲int  
sizeof(2 + 3.14); //值爲8,等價於sizeof(double),因爲此表達式的結果的類型爲double 

這是對於sizeof函數做的一個簡單的例子,下面就分幾種類型來總結一下:
1. 基本數據類型的sizeof
這裏的基本數據類型是指short、int、long、float、double這樣的簡單內置數據類型。
由於它們的內存大小是和系統相關的,所以在不同的系統下取值可能不同
2. 結構體的sizeof
結構體的sizeof涉及到字節對齊問題。
爲什麼需要字節對齊?計算機組成原理教導我們這樣有助於加快計算機的取數速度,否則就得多花指令週期了。爲此,編譯器默認會對結構體進行處理(實際上其它地方的數據變量也是如此),讓寬度爲2的基本數據類型(short等)都位於能被2整除的地址上,讓寬度爲4的基本數據類型(int等)都位於能被4整除的地址上,依次類推。這樣,兩個數中間就可能需要加入填充字節,所以整個結構體的sizeof值就增長了。
字節對齊的細節和編譯器的實現相關,但一般而言,滿足三個準則:
1) 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除。
2) 結構體的每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要,編譯器會在成員之間加上填充字節(internal adding)。
3) 結構體的總大小爲結構體最寬基本類型成員大小的整數倍,如有需要,編譯器會在最末一個成員後加上填充字節(trailing padding)。
注意:空結構體(不含數據成員)的sizeof值爲1。試想一個“不佔空間“的變量如何被取地址、兩個不同的“空結構體”變量又如何得以區分呢,於是,“空結構體”變量也得被存儲,這樣編譯器也就只能爲其分配一個字節的空間用於佔位了。
例子:

struct S1  
{  
    char a;  
    int b;  
};  
sizeof(S1); //值爲8,字節對齊,在char之後會填充3個字節。  

struct S2  
{  
    int b;  
    char a;  
};  
sizeof(S2); //值爲8,字節對齊,在char之後會填充3個字節。  

struct S3  
{  
};  
sizeof(S3); //值爲1,空結構體也佔內存。
  1. 聯合體的sizeof
    結構體在內存組織上市順序式的,聯合體則是重疊式,各成員共享一段內存;所以整個聯合體的sizeof也就是每個成員sizeof的最大值。
    例子:
union u  
{  
    int a;  
    float b;  
    double c;  
    char d;  
};  

sizeof(u); //值爲8
  1. 數組的sizeof
    數組的sizeof值等於數組所佔用的內存字節數。
    注意:1)當字符數組表示字符串時,其sizeof值將’/0’計算進去。
    2)當數組爲形參時,其sizeof值相當於指針的sizeof值。
    例子1:
char a[10];  
char n[] = "abc";   

cout<<"char a[10]                 "<<sizeof(a)<<endl;//數組,值爲10  

cout<<"char n[] = /"abc/"           "<<sizeof(n)<<endl;//字符串數組,將'/0'計算進去,值爲4 
void func(char a[3])  
{  
    int c = sizeof(a); //c = 4,因爲這裏a不在是數組類型,而是指針,相當於char *a。  
}  

void funcN(char b[])  
{  
    int cN = sizeof(b); //cN = 4,理由同上。  
  1. 指針的sizeof
    指針是用來記錄另一個對象的地址,所以指針的內存大小當然就等於計算機內部地址總線的寬度。
    在32位計算機中,一個指針變量的返回值必定是4。
    指針變量的sizeof值與指針所指的對象沒有任何關係。
    例子:
char *b = "helloworld";  
char *c[10];  
double *d;  
int **e;  
void (*pf)();    

cout<<"char *b = /"helloworld/"     "<<sizeof(b)<<endl;//指針指向字符串,值爲4  
cout<<"char *b                    "<<sizeof(*b)<<endl; //指針指向字符,值爲1  
cout<<"double *d                  "<<sizeof(d)<<endl;//指針,值爲4  
cout<<"double *d                  "<<sizeof(*d)<<endl;//指針指向浮點數,值爲8  
cout<<"int **e                  "<<sizeof(e)<<endl;//指針指向指針,值爲4  
cout<<"char *c[10]                "<<sizeof(c)<<endl;//指針數組,值爲40  
cout<<"void (*pf)();              "<<sizeof(pf)<<endl;//函數指針,值爲4 
  1. 函數的sizeof
    sizeof也可對一個函數調用求值,其結果是函數返回值類型的大小,函數並不會被調用。
    對函數求值的形式:sizeof(函數名(實參表))
    注意:1)不可以對返回值類型爲空的函數求值。
    2)不可以對函數名求值。
    3)對有參數的函數,在用sizeof時,須寫上實參表。
    例子:
#include <iostream>  
using namespace std;  

float FuncP(int a, float b)  
{  
    return a + b;  
}  

int FuncNP()  
{  
    return 3;  
}  

void Func()  
{  
}  

int main()  
{  
cout<<sizeof(FuncP(3, 0.4))<<endl; //OK,值爲4,sizeof(FuncP(3,0.4))相當於sizeof(float)  
cout<<sizeof(FuncNP())<<endl; //OK,值爲4,sizeof(FuncNP())相當於sizeof(int)  
/*cout<<sizeof(Func())<<endl; //error,sizeof不能對返回值爲空類型的函數求值*/  
/*cout<<sizeof(FuncNP)<<endl; //error,sizeof不能對函數名求值*/  
} 

例子:

class A
{
};

class B
{
public:
        B() {}
        ~B() {}
};

class C
{
public:
        C() {}
        virtual ~C() {}
};

int _tmain(int argc, _TCHAR* argv[])
{
        printf("%d, %d, %d\n", sizeof(A), sizeof(B), sizeof(C));
        return 0;
}

得到的結果是1, 1, 4 class A是一個空類型,它的實例不包含任何信息,本來求sizeof應該是0。但當我們聲明該類型的實例的時候,它必須在內存中佔有一定的空間

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