c++ --> sizeof()使用小結


sizeof()使用小結

 

特性0:sizeof是運算符,不是函數

  sizeof最基本特性,后面的很多特性都是受到這個特性的影響,正因為sizeof不是函數,因此不把它所要求得長度的對象叫做參數,習慣上叫做操作數。

 

特性1:sizeof不能求得void類型的長度

  不能用sizeof(void),這將導致編譯錯誤:illegalsizeof operand。因為無法聲明void類型的變量,可以試試void a; 編譯器會報錯:illegal use of type 'void'。聲明變量的一個重要作用就是告訴編譯器該變量需要多少存儲空間。但void是“空類型”,你可以理解成不知道存儲空間大小的類型。既然編譯器無法確定void類型的變量的存儲大小,那么它自然不讓你聲明這樣的變量。當然了,聲明void類型的指針是可以的!這就是特性2的內容。

 

特性2:sizeof能求得void類型的指針的長度

  編譯器可以確定void類型的指針所占用的存儲空間,大小是4byte,如sizeof(int*);sizeof(void*);sizeof(double*);sizeof(Person*);等等。指針也是變量,只不過這個變量很特殊,它是存放其他變量的地址的變量。又由於目前32位計算機平台上的程序段的尋址范圍都是4GB,尋址的最小單元是byte,4GB等於232Byte,這么多的內存其地址如果編碼呢,只需要用32個bit就行了,而32bit = 32/8 = 4byte,也就是說只需要4byte就能存儲這些內存的地址了。因此對任何類型的指針變量進行sizeof運算其結果就是4!

 

特性3:sizeof能求得靜態分配內存的數組的長度!

  int a[10]; int n = sizeof(a); 假設sizeof(int)等於4,則n= 10*4=40;特別要注意:char ch[]=”abc”;sizeof(ch);結果為4,注意字符串數組末尾有’\0’!通常我們可以利用sizeof來計算數組中包含的元素個數,其做法是:int n = sizeof(a)/sizeof(a[0]); 非常需要注意的是對函數的形參數組使用sizeof的情況。舉例來說,假設有如下的函數:

void fun(int array[10])
{
     int n = sizeof(array);
}

  這里n等於4,事實上不管形參是int的型數組,還是float型數組,或者其他任何用戶自定義類型的數組,也不管數組包含多少個元素,這里的n都是4!原因是在函數參數傳遞時,數組被轉化成指針了,原因:假如直接傳遞整個數組的話,那么必然涉及到數組元素的拷貝(實參到形參的拷貝),當數組非常大時,這會導致函數執行效率極低!而只傳遞數組的地址(即指針)那么只需要拷貝4byte。

 

特性4:sizeof不能求得動態分配的內存的大小!

  假如有如下語句:int*a = new int[10]; int n = sizeof(a); 那么n的值是多少呢?是40嗎?答案是否定的!其實n等於4,因為a是指針,在特性2中講過:在32位平台下,所有指針的大小都是4byte!很多人都認為數組名就是指針,其實不然,二者有很多區別的,可參看《c專家編程》。

  有人認為sizeof是編譯時進行求值的,並給出理由:語句 int array[sizeof(int)*10]; 能編譯通過。但在編譯器(如DEV C++)中定義動態數組,即:語句:int num; cin>>num;  int arrary[num];是對的(注意在vc6.0中是錯的)。同樣在DEV C++中對剛才的array利用語句int n=sizeof(array);cout<<n<<endl來求大小,結果編譯通過,運行時輸入num的值10之后,輸出n等於40!在這里很明顯num的值是運行時才輸入的,因此sizeof不可能在編譯時就求得array的大小!這樣一來sizeof又變成是運行時求值的了。

  那么到底sizeof是編譯時求值還是運行時求值呢?最開初c標准規定sizeof只能編譯時求值,后來c99又補充規定sizeof可以運行時求值。但值得注意的是,即便是在實現了c99標准的DEV C++中仍然不能用sizeof求得動態分配的內存的大小!

 

特性5:sizeof不能對不完整的數組求長度!

  在闡述該特性之前,我們假設有兩個源文件:file1.cpp和file2.cpp,其中file1.cpp中有如下的定義:

int arrayA[10] = {1,2,3,4,5,6,7,8,9,10};
int arrayB[10] = {11,12,13,14,15,16,17,18,19,20};

  file2.cpp包含如下幾個語句:

extern arrayA[];
extern arrayB[10];
cout<<sizeof(arrayA)<<endl;       //編譯出錯!!
cout<<sizeof(arrayB)<<endl;       //40

  原因是sizeof(arrayA)試圖求不完整數組的大小。這里的不完整的數組是指數組大小沒有確定的數組!sizeof運算符的功能就是求某種對象的大小,然而聲明:extern int arrayA[]只是告訴編譯器arrayA是一個整型數組,但是並沒告訴編譯器它包含多少個元素,因此對file2.cpp中的sizeof來說它無法求出arrayA的大小,所以編譯器干脆不讓你通過編譯。

  那為什么sizeof(arrayB)又可以得到arraryB的大小呢?關鍵就在於在file2.cpp中其聲明時使用externint arrayB[10]明確地告訴編譯器arrayB是一個包含10個元素的整型數組,因此大小是確定的。

 

特性6:當表達式作為sizeof的操作數時,它返回表達式的計算結果的類型大小,但是它不對表達式求值!

  為了說明這個問題,我們來看如下的程序語句:

char ch = 1;
int num = 1;
int n1 = sizeof(ch + num);     //4
int n2 = sizeof(ch = ch+num);  //1, 其中ch = 1

  執行上面的程序之后,n1等於4,n2等於1,ch等於1。由於默認類型轉換的原因,表達式ch+num的計算結果的類型是int,因此n1的值為4!而表達式ch=ch+num;的結果的類型是char,雖然在計算ch+num時,結果為int,但是當把結果賦值給ch時又進行了類型轉換,因此表達式的最終類型還是char,所以n2等於1。n1, n2的值分別為4和1,其原因正是因為sizeof返回的是表達式計算結果的類型大小,而不是表達式中占用最大內存的變量的類型大小!

 

特性7:sizeof可以對函數調用求大小,並且求得的大小等於返回類型的大小,但是不執行函數體!

  假設有如下函數:

int fun(int& num,const int& inc)
{
     float div = 2.0;
     double ret =0;
     num = num+inc;
     ret = num/div;
     return ret;
}

int a = 3;
int b = 5;
cout << sizeof(fun(a,b)) << endl;  //4,操作對象是函數調用時,不執行函數體
cout << a << endl;                 //3

  首先sizeof(fun(a,b))的值:其正確是4,因為用sizeof求函數調用的大小時,它得到的是函數返回類型的大小,而fun(a,b)的返回類型是int,sizeof(int)等於4。函數的返回類型和返回值的類型是不一樣的。來看語句:cout<<sizeof(fun);其答案是多少呢?其實它得不到答案,原因是編譯就通不過!原因待補充。

 

特性8:sizeof求得的結構體(及其對象)的大小並不等於各個數據成員對象的大小之和!

  結構體的大小跟結構體成員對齊有密切關系,而並非簡單地等於各個成員的大小之和!比如對如下結構體兩個結構體A、B使用sizeof的結果分別是:16,24。可以看出sizeof(B)並不等於sizeof(int)+sizeof(double)+sizeof(int)=16。

struct A{

         int num1;

         int num2;

         double num3;

};

struct B{

         int num1;

         double num3;

         int num2;

};

其規則如下:

  1.結構體的大小等於結構體內最大成員大小的整數倍

  2.結構體內的成員的首地址相對於結構體首地址的偏移量是其類型大小的整數倍,如double成員相對於結構體的首地址的地址偏移量應該是8的倍數。

  3.為了滿足規則1和2編譯器會在結構體成員之后進行字節填充!

  在進行設計時,要安排好結構體中各個成員的順序,順序略有差異,可能導致B比A多消耗了50%的空間!

 

特性9:sizeof不能用於求結構體的位域成員的大小,但是可以求得包含位域成員的結構體的大小!

  首先解釋一下什么是位域:類型的大小都是以字節(byte)為基本單位的,比如sizeof(char)為1byte,sizeof(int)為4byte等。但bool類型只取值true和false,按理所只用1bit(即1/8byte)就夠了,但事實上sizeof(bool)等於1。因此可以認為bool變量浪費了87.5%(7/8)的存儲空間!這在某些存儲空間有限的設備(比如嵌入式設備)上是不合適的,為此需要提供一種能對變量的存儲空間精打細算的機制,這就是位域。簡單來說,在結構體的成員變量后面跟上的一個冒號 + 一個整數,就代表位域,請看如下的結構體:

struct A
{
     Bool b:1;
     char ch1:4;
     char ch2:4;
}item; 

  該結構體試圖讓bool類型的變量b只占用1個bit,讓ch1和ch2分別只占用4個bit,以此來達到對內存精打細算的功能c語言規定位域只能用於int,signed int或者unsigned int類型,C++又補充了char和long類型!你不能這樣使用位域:floatf:8;這是不能通過編譯的。並且位域變量不能在函數或者全局區定義,只能在結構體,自定義類,聯合(union)中使用!

  基於上面的結構體,語句sizeof(item.b)和sizeof(item.ch1)等對位域成員求大小的語句均不能通過編譯。其原因能再本篇的概論中找到:sizeof以byte為單位返回操作數的大小!那么sizeof(A)能否通過編譯呢?對包含位域的結構體是可以使用sizeof求其大小的,但其求值規則比較復雜,不僅涉及到成員對齊,還與具體編譯環境有關!在這里你只需要知道可以對包含位域的結構體使用sizeof求其大小。

 

參考:http://blog.csdn.net/w57w57w57/article/details/6626840

版權:w57w57w57

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM