天天看點

sizeof用法總結(個人感覺非常好的一篇文章)

  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是不需要的。