深入理解sizeof+C語言數據類型+內存補齊

第一個例子:
01.char* ss = "0123456789";
02.sizeof(ss) 結果 4 ===》ss是指向字符串常量的字符指針
03.sizeof(*ss) 結果 1 ===》*ss是第一個字符
04. 
05.char ss[] = "0123456789";
06.sizeof(ss) 結果 11 ===》ss是數組,計算到\0位置,因此是10+1
07.sizeof(*ss) 結果 1 ===》*ss是第一個字符
08. 
09.char ss[100] = "0123456789";
10.sizeof(ss) 結果是100 ===》ss表示在內存中的大小 100×1
11.strlen(ss) 結果是10 ===》strlen是個函數內部實現是用一個循環計算到\0爲止之前
12. 
13.int ss[100] = "0123456789";
14.sizeof(ss) 結果 400 ===》ss表示再內存中的大小 100×4
15.strlen(ss) 錯誤 ===》strlen的參數只能是char* 且必須是以''\0''結尾的
16. 
17.char q[]="abc";
18.char p[]="a\n";
19.sizeof(q),sizeof(p),strlen(q),strlen(p);

20.結果是 4 3 3 2


第二個例子:

數組作爲參數傳給函數時傳的是指針而不是數組,傳遞的是數組的首地址,如:
1.fun(char [8])
2.fun(char [])都等價於 fun(char *) 在C++裏傳遞數組永遠都是傳遞指向數組首元素的指針,

void printfsize(char p[100])
{
    std::cout<<"p[100] size"<<sizeof(p)<<" "<<std::endl;
}

輸出結果爲 4.

void test_size(char (&param)[10])

{

   int size_3 = sizeof(param);

   std::cout<<"size_3"<<size_3<<std::endl;

}

輸出結果爲 10.

int size_1 = sizeof(char&);    --->    1

int size_2 = sizeof(char[2]); --->    2


第三個例子:

union分到的內存等於它佔內存最大的那個成員所需內存。

union fuck_union

{

    short a,b;

    unsigned c:2, d:1;

};

sizeof(fuck_union)  輸出 4。

union fuck_union

{

    short a,b;

};

sizeof(fuck_union)  輸出 2。


第四個例子:

sizeof還可以用函數做參數,比如:
1.short f();
2.printf("%d\n", sizeof(f()));

輸出的結果是sizeof(short),即2。

int f()  輸出結果爲4。

class A

{

void FuckB(){};

};

printf("%d\n",  sizeof(&A::FuckB));

輸出 4。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

字符對齊

計算結構變量的大小就必須討論數據對齊問題。爲了CPU存取的速度最快(這同CPU取數操作有關,詳細的介紹可以參考一些計算機原理方面的書),C++在 處理數據時經常把結構變量中的成員的大小按照4或8的倍數計算,這就叫數據對齊(data alignment)。這樣做可能會浪費一些內存,但理論上速度快了。當然這樣的設置會在讀寫一些別的應用程序生成的數據文件或交換數據時帶來不便。 visual studio裏的內存補齊是在項目屬性-》C/C++-》代碼生成-》結構成員對齊,一般是默認值,還可以設爲1、2、4、8、16字節,分別表示爲結構 體(struct、class,不包括union,union分到的內存等於它佔內存最大的那個成員所需內存)內存分配時的最小單位爲1、2、4、8、 16字節,但是如果設置的值比結構體中佔內存最大的那個成員所需內存還大,則設置無效。默認值就是指以佔內存最大的那個成員所需內存爲最小單位。


class X

{
        char c;    //1byte
        int i;        //4byte
        short s;   //2byte

};

輸出是 12


值得注意的是
class X

{
    char c;   //1byte
    short s;  //2byte
    int i;       //4byte

}

輸出是 8


    class X{
        char c;//1byte

        short s;//2byte
        int i;//4byte

         };

 

設置的值             1         2        4         8        16 
    
默認值sizeof(X)    7        8         8        8         8 



















第二個例子:
01.class X
02.{
03.int i;
04.int j;
05.char k;
06.};
07.X x;
08.cout<<sizeof(X)<<endl; 結果 12 ===》內存補齊
09.cout<<sizeof(x)<<endl; 結果 12 同上

第三個例子:
1.char szPath[MAX_PATH]

如果在函數內這樣定義,那麼sizeof(szPath)將會是MAX_PATH,但是將szPath作爲虛參聲明時(void fun(char szPath[MAX_PATH])),sizeof(szPath)卻會是4(指針大小)

三、sizeof深入理解。

1.sizeof操作符的結果類型是size_t,它在頭文件中typedef爲unsigned int類型。該類型保證能容納實現所建立的最大對象的字節大小。

2.sizeof是算符,strlen是函數。

3.sizeof可以用類型做參數,strlen只能用char*做參數,且必須是以''\0''結尾的。sizeof還可以用函數做參數,比如:
1.short f();
2.printf("%d\n", sizeof(f()));

輸出的結果是sizeof(short),即2。

4.數組做sizeof的參數不退化,傳遞給strlen就退化爲指針了。

5.大部分編譯程序 在編譯的時候就把sizeof計算過了 是類型或是變量的長度這就是sizeof(x)可以用來定義數組維數的原因
1.char str[20]="0123456789";
2.int a=strlen(str); //a=10;
3.int b=sizeof(str); //而b=20;

6.strlen的結果要在運行的時候才能計算出來,時用來計算字符串的長度,不是類型佔內存的大小。

7.sizeof後如果是類型必須加括弧,如果是變量名可以不加括弧。這是因爲sizeof是個操作符不是個函數。

8.當適用了於一個結構類型時或變量, sizeof 返回實際的大小, 當適用一靜態地空間數組, sizeof 歸還全部數組的尺 寸。 sizeof 操作符不能返回動態地被分派了的數組或外部的數組的尺寸

9.數組作爲參數傳給函數時傳的是指針而不是數組,傳遞的是數組的首地址,如:
1.fun(char [8])
2.fun(char [])

都等價於 fun(char *) 在C++裏傳遞數組永遠都是傳遞指向數組首元素的指針,編譯器不知道數組的大小如果想在函數內知道數組的大小, 需要這樣做:進入函數後用memcpy拷貝出來,長度由另一個形參傳進去
1.fun(unsiged char *p1, int len)
2.{
3.unsigned char* buf = new unsigned char[len+1]
4.memcpy(buf, p1, len);
5.}

有關內容見: C++ PRIMER?

10.計算結構變量的大小就必須討論數據對齊問題。爲了CPU存取的速度最快(這同CPU取數操作有關,詳細的介紹可以參考一些計算機原理方面的書),C++在處理數據時經常把結構變量中的成員的大小按照4或8的倍數計算,這就叫數據對齊(data alignment)。這樣做可能會浪費一些內存,但理論上速度快了。當然這樣的設置會在讀寫一些別的應用程序生成的數據文件或交換數據時帶來不便。MS VC++中的對齊設定,有時候sizeof得到的與實際不等。一般在VC++中加上#pragma pack(n)的設定即可.或者如果要按字節存儲,而不進行數據對齊,可以在Options對話框中修改Advanced compiler頁中的Data alignment爲按字節對齊。

11.sizeof操作符不能用於函數類型,不完全類型或位字段。不完全類型指具有未知存儲大小的數據類型,如未知存儲大小的數組類型、未知內容的結構或聯合類型、void類型等。如sizeof(max)若此時變量max定義爲int max(),sizeof(char_v) 若此時char_v定義爲char char_v [MAX]且MAX未知,sizeof(void)都不是正確形式

四、結束語

sizeof使用場合。

1.sizeof操作符的一個主要用途是與存儲分配和I/O系統那樣的例程進行通信。例如: 
1.void *malloc(size_t size), 
2.size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。

2.用它可以看看一類型的對象在內存中所佔的單元字節。
1.void * memset(void * s,int c,sizeof(s))

3.在動態分配一對象時,可以讓系統知道要分配多少內存。

4.便於一些類型的擴充,在windows中就有很多結構內型就有一個專用的字段是用來放該類型的字節大小。

5.由於操作數的字節數在實現時可能出現變化,建議在涉及到操作數字節大小時用sizeof來代替常量計算。

6.如果操作數是函數中的數組形參或函數類型的形參,sizeof給出其指針的大小。 

    計算結構變量的大小就必須討論數據對齊問題。爲了CPU存取的速度最快(這同CPU取數操作有關,詳細的介紹可以參考一些計算機原理方面的書),C++在處理數據時經常把結構變量中的成員的大小按照4或8的倍數計算,這就叫數據對齊(data alignment)。這樣做可能會浪費一些內存,但理論上速度快了。當然這樣的設置會在讀寫一些別的應用程序生成的數據文件或交換數據時帶來不便。visual studio裏的內存補齊是在項目屬性-》C/C++-》代碼生成-》結構成員對齊,一般是默認值,還可以設爲1、2、4、8、16字節,分別表示爲結構體(struct、class,不包括union,union分到的內存等於它佔內存最大的那個成員所需內存)內存分配時的最小單位爲1、2、4、8、16字節,但是如果設置的值比結構體中佔內存最大的那個成員所需內存還大,則設置無效。默認值就是指以佔內存最大的那個成員所需內存爲最小單位

      代碼里加#pragma pack (n) //n:1 2 4 8 16也是一樣的效果

     class X{
        char c;//1byte
        int i;//4byte

        short s;//2byte

         };

設置的值    1          2        4    8  16 
    
默認值  sizeof(X)
    

7    8    12   12  12  12
    
值得注意的是

      class X{
        char c;//1byte

        short s;//2byte
        int i;//4byte

         };

 

設置的值    1          2        4    8  16 
    
默認值  sizeof(X)  7  8  8  8  8  8  8

設置爲1、2的時候都好理解,設置爲4的時候爲什麼不是12呢?因爲編譯器按順序爲成員變量分配內存,char+short總共3byte,還不到4byte,補齊爲4byte即可,再加4byteint,總共8byte
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章