sizeof 用法總結
以下運作環境都是一般的,在32位編譯環境中 1 ,基本資料類型的sizeof cout<<sizeof(char)<<endl; 結果是1 cout<<sizeof(int)<<endl; 結果是4 cout<<sizeof(unsigned int)<<endl; 結果是4 cout<<sizeof(long int)<<endl; 結果是4 cout<<sizeof(short int)<<endl; 結果是2 cout<<sizeof(float)<<endl; 結果是4 cout<<sizeof(double)<<endl; 結果是8 2 ,指針變量的sizeof char *pc ="abc"; sizeof( pc ); // 結果為 4 sizeof(*pc); // 結果為 1 int *pi; sizeof( pi ); //結果為 4 sizeof(*pi); //結果為 4 char **ppc = &pc; sizeof( ppc ); // 結果為 4 sizeof( *ppc ); // 結果為 4 sizeof( **ppc ); // 結果為 1 void (*pf)();// 函數指針 sizeof( pf );// 結果為 4 3 ,數組的sizeof數組的sizeof值等于數組所占用的記憶體位元組數,如: char a1[] = "abc"; int a2[3]; sizeof( a1 ); // 結果為4,字元 末尾還存在一個NULL終止符 sizeof( a2 ); // 結果為3*4=12(依賴于int) 寫到這裡,提一問,下面的c3,c4值應該是多少呢 void foo3(char a3[3]) { int c3 = sizeof( a3 ); // c3 == 4 } void foo4(char a4[]) { int c4 = sizeof( a4 ); // c4 == 4 } 也許當你試圖回答c4的值時已經意識到c3答錯了,是的,c3!=3。這裡函數參數a3已不再是數組類型,而是蛻變成指針,相當于char* a3,為什麼仔細想想就不難明白,我們調用函數foo1時,程式會在棧上配置設定一個大小為3的數組嗎不會!數組是“傳址”的,調用者隻需将實參的位址傳遞過去,是以a3自然為指針類型(char*),c3的值也就為4。 4 ,結構體的sizeof struct MyStruct { double dda1; char dda; int type }; // 結果為16,為上面的結構配置設定空間的時候,VC根據成員變量出現的順序和對齊方式,先為第一個成員dda1配置設定空間,其起始位址跟結構的起始位址相同(剛好偏移量0剛好為sizeof(double)的倍數),該成員變量占用sizeof(double)=8個位元組;接下來為第二個成員dda配置設定空間,這時下一個可以配置設定的位址對于結構的起始位址的偏移量為8,是sizeof(char)的倍數,是以把dda存放在偏移量為8的地方滿足對齊方式,該成員變量占用sizeof(char)=1個位元組;接下來為第三個成員type配置設定空間,這時下一個可以配置設定的位址對于結構的起始位址的偏移量為9,不是sizeof(int)=4的倍數,為了滿足對齊方式對偏移量的限制問題,VC自動填充3個位元組(這三個位元組沒有放什麼東西),這時下一個可以配置設定的位址對于結構的起始位址的偏移量為12,剛好是sizeof(int)=4的倍數,是以把type存放在偏移量為12的地方,該成員變量占用sizeof(int)=4個位元組;這時整個結構的成員變量已經都配置設定了空間,總的占用的空間大小為:8+1+3+4=16,剛好為結構的位元組邊界數(即結構中占用最大空間的類型所占用的位元組數sizeof(double)=8)的倍數,是以沒有空缺的位元組需要填充。是以整個結構的大小為:sizeof(MyStruct)=8+1+3+4=16,其中有3個位元組是VC自動填充的,沒有放任何有意義的東西。 5 ,含位域結構體的sizeof 示例1: struct BF1 { char f1 : 3; char f2 : 4; char f3 : 5; }; 其記憶體布局為: |_f1__|__f2__|_|____f3___|____| |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| 0 3 7 8 1316 位域類型為char,第1個位元組僅能容納下f1和f2,是以f2被壓縮到第1個位元組中,而f3隻能從下一個位元組開始。是以sizeof(BF1)的結果為2。 6 ,含有聯合體的結構體的sizeof struct s1 { char *ptr,ch; //有指針變成4+4 union A //後面跟了A定義了一個類型,不占記憶體,而後面不跟A,是聲明了結構體的一個成員,占記憶體, { short a,b; unsigned int c:2, d:1; }; struct s1* next; //指針占4 };//這樣是8+4=12個位元組 struct s1 { char *ptr,ch; union // 聯合體是結構體的成員,占記憶體,并且最大類型是unsigned int,占4 { short a,b; unsigned int c:2, d:1; }; struct s1* next; };//這樣是8+4+4=16個位元組 7 ,結構體體含有結構體的sizeof struct S1 { char c; int i; }; struct S3 { char c1; S1 s; char c2; }; cout<<sizeof(S3); //S3=16 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。 8 ,帶有#pragma pack的sizeof 它是用來調整結構體對齊方式的,不同編譯器名稱和用法略有不同,VC6中通過#pragma pack實作,也可以直接修改/Zp編譯開關。#pragma pack的基本用法為:#pragma pack( n ),n為位元組對齊 數,其取值為1、2、4、8、16,預設是8,如果這個值比結構體成員的sizeof值小,那麼該成員的偏移量應該以此值為準,即是說,結構體成員的偏移量應該取二者的最小值, 再看示例: #pragma pack(push) // 将目前pack設定壓棧儲存 #pragma pack(2)// 必須在結構體定義之前使用 struct S1 { char c; int i; }; struct S3 { char c1; S1 s; char c2 }; #pragma pack(pop) // 恢複先前的pack設定 計算sizeof(S1)時,min(2, sizeof(i))的值為2,是以i的偏移量為2,加上sizeof(i) 等于6,能夠被2整除,是以整個S1的大小為6。 同樣,對于sizeof(S3),s的偏移量為2,c2的偏移量為8,加上sizeof(c2)等于9,不能 被2整除,添加一個填充位元組,是以sizeof(S3)等于10。 9 ,空結構體的sizeof struct S5 { }; sizeof( S5 ); // 結果為1 10 ,類的sizeof 類的sizeof值等于類中成員變量所占用的記憶體位元組數。如: **************************************************************** class A { public: int b; float c; char d; }; int main(void) { A object; cout << "sizeof(object) is " << sizeof(object) << endl; return 0 ; } ************************************************************ 輸出結果為12(我的機器上sizeof(float)值為4,位元組對其前面已經講過)。 不過需要注意的是,如果類中存在靜态成員變量,結果又會是什麼樣子呢? ************************************************************ class A { public: static int a; int b; float c; char d; }; int main() { A object; cout << "sizeof(object) is " << sizeof(object) << endl; return 0 ; } ************************************************************ 16?不對。結果仍然是12. 因為在程式編譯期間,就已經為static變量在靜态存儲區域配置設定了記憶體空間,并且這塊記憶體在程式的整個運作期間都存在。 而每次聲明了類A的一個對象的時候,為該對象在堆上,根據對象的大小配置設定記憶體。 如果類A中包含成員函數,那麼又會是怎樣的情況呢?看下面的例子 ************************************************************ class A { public: static int a; int b; float c; char d; int add(int x,int y) { return x+y; } }; int main() { A object; cout << "sizeof(object) is " << sizeof(object) << endl; b = object.add(3,4); cout << "sizeof(object) is " << sizeof(object) << endl; return 0 ; } ************************************************************ 結果仍為12。 因為隻有非靜态類成員變量在新生成一個object的時候才需要自己的副本。 是以每個非靜态成員變量在生成新object需要記憶體,而function是不需要的。 |