詳解C++ sizeof(上)
sizeof是C/C++中的一個操作符(operator),其作用是返回一個物件或者型別所佔的記憶體位元組數,使用頻繁,有必須對其有個全面的瞭解。
1.sizeof的基本語法
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
2.sizeof計算基本型別與表示式
sizeof計算物件的大小實際上是轉換成物件型別進行計算,也就是說,同種型別的不同物件其sizeof值都是一致的。這裡,物件可以進一步延伸至表示式,即sizeof可以對一個表示式求值,編譯器根據表示式的最終結果型別來確定大小,sizeof是編譯時進行運算,與執行時無關,不會對錶達式進行計算。考察如下程式碼:
#include <iostream> using namespace std; int main(int argc,char* argv[]) { cout<<"sizeof(char)="<<sizeof(char)<<endl; cout<<"sizeof(short)="<<sizeof(short int)<<endl; cout<<"sizeof(int)="<<sizeof(int)<<endl; cout<<"sizeof(long)="<<sizeof(long int)<<endl; cout<<"sizeof(long long)="<<sizeof(long int int)<<endl; cout<<"sizeof(float)="<<sizeof(float)<<endl; cout<<"sizeof(double)="<<sizeof(double)<<endl; int i=8; cout<<"i="<<i<<endl; cout<<"sizeof(i)="<<sizeof(i)<<endl; cout<<"sizeof(i)="<<sizeof(i=5)<<endl; cout<<"i="<<i<<endl; }
在64bits的Windows下執行結果如下:
sizeof(char)=1
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=4
sizeof(float)=4
sizeof(double)=8
i=8
sizeof(i)=4
sizeof(i)=4
i=8
觀察以上程式需要注意兩點。
(1)i的值並未發生改變,表明sizeof括號內的表示式並沒有執行,sizeof在編譯時求其表示式的運算結果的型別,sizeof運算與執行時無關。sizeof(i)等價於sizeof(int),sizeof(i=5)等價於sizeof(int),也就是說在可執行程式碼中,並不包含i=5這個表示式,它早在編譯階段就被處理了。
3.sizeof計算指標變數
指標是C/C++的靈魂,它記錄了一個物件的地址。指標變數的位寬等於機器字長,機器字長由CPU暫存器位數決定。在32位系統中,一個指標變數的返回值為4位元組,64位系統中指標變數的sizeof結果為8位元組。
char* pc = "abc"; int* pi=new int[10]; string* ps; char** ppc = &pc; void (*pf)(); // 函式指標 char testfunc() { return ‘k'; } sizeof( pc ); // 結果為4 sizeof( pi ); // 結果為4 sizeof( ps ); // 結果為4 sizeof( ppc ); // 結果為4 sizeof( pf ); // 結果為4 sizeof( &testfunc ); // 結果為4 sizeof( testfunc ()); // 結果為1 sizeof(*( testfunc) ()); // 結果為1
考察以上程式碼,得出如下結論:
(1)指標變數的sizeof值與指標所指的物件型別沒有任何關係,與指標申請多少空間沒有關係,所有的指標變數所佔記憶體大小均相等。那為什麼在本機64bits系統下,指標變數大小仍然是4個位元組,因為使用32位編譯器編譯得到程式是32位,故指標大小是4位元組,可自行修改編譯器版本,不再贅述。
(2)&testfunc代表一個函式指標,指標大小是4,所以sizeof(&testfunc)==4。testfunc()代表一次函式呼叫,返回值型別是char,所以sizeof(testfunc())==sizeof(char)==1。testfunc名本身就是一個函式指標,所以(*testfunc)()
也是一次函式呼叫,sizeof((*testfunc)())==sizeof(char)==1
。
4.sizeof計算陣列
當sizeof作用於陣列時,求取的是陣列所有元素所佔用的大小。參考如下程式碼:
int A[3][5]; char c[]="123456"; double*(*d)[3][6]; cout<<sizeof(A)<<endl; //輸出60 cout<<sizeof(A[4])<<endl; //輸出20 cout<<sizeof(A[0][0])<<endl;//輸出4 cout<<sizeof(c)<<endl; //輸出7 cout<<sizeof(d)<<endl; //輸出4 cout<<sizeof(*d)<<endl; //輸出72 cout<<sizeof(**d)<<endl; //輸出24 cout<<sizeof(***d)<<endl; //輸出4 cout<<sizeof(****d)<<endl; //輸出8
考察以上程式碼,得出如下結論:
(1)A的資料型別是int[3][5]
,A[4]
的資料型別是int[5]
,A[0][0]
資料型別是int。所以
sizeof(A)==sizeof(int[3][5])==3*5*sizeof(int)==60 sizeof(A[4])==sizeof(int[5])=5*sizeof(int)==20 sizeof(A[0][0])==sizeof(int)==4
儘管A[4]
的下標越界,但不會造成執行時錯誤,因為sizeof運算只關心資料型別,在編譯階段就已經完成。
(2)由於字串以空字元'\0'結尾,所以c的資料型別是char[7],所以sizeof(c)=sizeof(char[7])==7。
(3)d是一個指標,不管它指向的物件是什麼資料型別,自身大小永遠是4,所以sizeof(d)==4。sizeof(*d)的資料型別是double*[3][6]
,所以
sizeof(*d)==sizeof(double*[3][6])==3*6*sizeof(double*)==18*4==72
同理,可以推算出
sizeof(**d)==sizeof(double*[6])==6*sizeof(double*)==24 sizeof(***d)==sizeof(double*)==4 sizeof(****d)=sizeof(double)==8
當陣列作為函式形參時,下面的i和j的值應該是多少呢?
void foo1(char a1[3]) { int i = sizeof( a1 ); // i == ? } void foo2(char a2[]) { int j = sizeof( a2); // j == ? }
也許當你試圖回答j的值時已經意識到i答錯了,是的,i!=3。這裡函式引數a1已不再是陣列型別,而是蛻變成指標,相當於char* a1,為什麼?仔細想想就不難明白,我們呼叫函式foo1時,程式會在棧上分配一個大小為3的陣列嗎?不會!陣列是“傳址”的,呼叫者只需將實參的地址傳遞過去,所以a1自然為指標型別(char*),i的值也就為4,同樣j也是4。
以上就是詳解C++ sizeof(上)的詳細內容,更多關於C++ sizeof的資料請關注我們其它相關文章!