sizeof 乃 C/C++ 中的一個操作符(operator)是也。簡單說其作用就是返回一個對象或者類型所佔的記憶體位元組數,傳回值類型為size_t
文法:
sizeof有三種文法形式,如下:
1) sizeof( object ); // sizeof( 對象 );
2) sizeof( type_name ); // sizeof( 類型 );
3) sizeof object; // sizeof 對象;
所以:
int i;
sizeof( i ); // ok
sizeof i; // ok
sizeof( int ); // ok
sizeof int; // error
sizeof可以對一個運算式求值。編譯器根據運算式的最終結果類型來確定大小,一般不會對錶達式進行計算。
char fun()<br />{<br />cout<<"fun()"<<endl;<br />return 'c';<br />}</p><p>void main()<br />{<br />cout<<sizeof(fun())<<endl;//輸出1,fun()返回char型,但是並未列印"fun()",即fun未執行<br />cout<<sizeof(2)<<endl;//輸出4,2為整形<br />cout<<sizeof(2.0+3)<<endl;//輸出8,2.0為double,3被提升至整形<br />cout<<sizeof("Grubby")<<endl;//輸出7,字串"Grubby"並沒有被認為是const char*<br />}
C99標準規定,函數、不能確定類型的運算式以及位域(bit-field)成員不能被計算sizeof值,即下面這些寫法都是錯誤的:
sizeof(void);
sizeof( foo );
void foo2() { }
sizeof( foo2() );
struct S
{
unsigned int f1 : 1;
unsigned int f2 : 5;
unsigned int f3 : 12;
};
sizeof( S.f1 );
電腦群組成原理教導我們,這樣有助於加快電腦的取數速度,否則就得多花指令周期了。
為此,編譯器預設會對結構體進行處理(實際上其它地方的資料變數也是如此),讓寬度為2的基礎資料型別 (Elementary Data Type)(short等)都位於能被2整除的地址上,讓寬度為4的基礎資料型別 (Elementary Data Type)(int等)都位於能被4整除的地址上。以此類推,這樣,兩個數中間就可能需要加入填充位元組,所以整個結構體的sizeof值就增長了。
位元組對齊的細節和編譯器實現相關,但一般而言,滿足三個準則:
1) 結構體變數的首地址能夠被其最寬基本類型成員的大小所整除;
2) 結構體每個成員相對於結構體首地址的位移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding);
3) 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充位元組(trailing padding)。
基本類型是指前面提到的像char、short、int、float、double這樣的內建資料類型。這裡所說的“資料寬度”就是指其sizeof的大小。由於結構體的成員可以是複合類型,比如另外一個結構體,所以在尋找最寬基本類型成員時,應當包括複合類型成員的子成員,而不是把複合成員看成是一個整體。但在確定複合類型成員的位移位置時則是將複合類型作為整體看待。
舉個例子
struct S1<br />{<br />int i;<br />char c;<br />};<br />struct S2<br />{<br />char c1;<br />S1 s;<br />char c2;<br />};<br />void main()<br />{<br />cout<<sizeof(S1)<<endl;<br />cout<<sizeof(S2)<<endl;<br />}
S1的最寬簡單成員的類型為int,S3在考慮最寬簡單類型成員時是將S1“打散”看的,所以S3的最寬簡單類型為int。這樣,通過S3定義的變數,其儲存空間首地址需要被4整除,整個sizeof(S3)的值也應該被4整除。
c1的位移量為0,s的位移量呢?這時s是一個整體,它作為結構體變數也滿足前面三個準則,所以其大小為8,位移量為4,c1與s之間便需要3個填充位元組,而c2與s之間就不需要了,所以c2的位移量為12,算上c2的大小為13,13是不能被4整除的,這樣末尾還得補上3個填充位元組。最後得到sizeof(S3)的值為16。
#pragma pack(4)
class TestC
{
public:
char a;
short b;
char c;
};
int nSize = sizeof(TestC);
按照正常的填充方式nSize的結果應該是8,為什麼結果顯示nSize為6呢?
事實上,很多人對#pragma pack的理解是錯誤的。
#pragma pack規定的對齊長度,實際使用的規則是:
結構,聯合,或者類的資料成員,第一個放在位移為0的地方,以後每個資料成員的對齊,按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。也就是說,當#pragma pack的值等於或超過所有資料成員長度的時候,這個值的大小將不產生任何效果。
而結構整體的對齊,則按照結構體中最大的資料成員 和 #pragma pack指定值 之間,較小的那個進行。
#pragma pack(4)
class TestC
{
public:
char a;//第一個成員,放在[0]位移的位置,
short b;//第二個成員,自身長2,#pragma pack(4),取2,按2位元組對齊,所以放在位移[2,3]的位置。
char c;//第三個,自身長為1,放在[4]的位置。
};
整個類的大小是5位元組,按照min(sizeof(short),4)位元組對齊,也就是2位元組對齊,結果是6
所以sizeof(TestC)是6。