1. 定義:
sizeof是c/c++中的乙個操作符(operator),簡單的說其作用就是返回乙個物件或者型別所佔的記憶體位元組數。
msdn上的解釋為:
the sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types).
this keyword returns a value of type size_t.
其返回值型別為size_t,在標頭檔案stddef.h中定義。這是乙個依賴於編譯系統的值,一般定義為
typedef unsigned int size_t;
世上編譯器林林總總,但作為乙個規範,它們都會保證char、signed char和unsigned char的sizeof值為1,畢竟char是我們程式設計能用的最小資料型別。
2. 語法:
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
既然寫法3可以用寫法1代替,為求形式統一以及減少我們大腦的負擔,第3種寫法,忘掉它吧!
實際上,sizeof計算物件的大小也是轉換成對物件型別的計算,也就是說,同種型別的不同物件其sizeof值都是一致的。這裡,物件可以進一步延伸至表示式,即sizeof可以對乙個表示式求值,編譯器根據表示式的最終結果型別來確定大小,一般不會對表示式進行計算。如:
sizeof( 2 );// 2的型別為int,所以等價於 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的型別為double,2也會被提公升成double型別,所以等價於 sizeof( double );
sizeof也可以對乙個函式呼叫求值,其結果是函式返回型別的大小,函式並不會被呼叫,我們來看乙個完整的例子:
char foo()
int main()
c99標準規定,函式、不能確定型別的表示式以及位域(bit-field)成員不能被計算sizeof值,即下面這些寫法都是錯誤的:
sizeof( foo );// error
void foo2()
sizeof( foo2() );// error
struct s
;sizeof( s.f1 );// error
3. sizeof的常量性
sizeof的計算發生在編譯時刻,所以它可以被當作常量表示式使用,如:
char ary[ sizeof( int ) * 10 ]; // ok
最新的c99標準規定sizeof也可以在執行時刻進行計算,如下面的程式在dev-c++中可以正確執行:
int n;
n = 10; // n動態賦值
char ary[n]; // c99也支援陣列的動態定義
printf("%d/n", sizeof(ary)); // ok. 輸出10
但在沒有完全實現c99標準的編譯器中就行不通了,上面的**在vc6中就通不過編譯。所以我們最好還是認為sizeof是在編譯期執行的,這樣不會帶來錯誤,讓程式的可移植性強些。
4. 基本資料型別的sizeof
這裡的基本資料型別指short、int、long、float、double這樣的簡單內建資料型別,由於它們都是和系統相關的,所以在不同的系統下取值可能不同,這務必引起我們的注意,盡量不要在這方面給自己程式的移植造成麻煩。
一般的,在32位編譯環境中,sizeof(int)的取值為4。
5. 指標變數的sizeof
學過資料結構的你應該知道指標是乙個很重要的概念,它記錄了另乙個物件的位址。既然是來存放位址的,那麼它當然等於計算機內部位址匯流排的寬度。所以在32位計算機中,乙個指標變數的返回值必定是4(注意結果是以位元組為單位),可以預計,在將來的64位系統中指標變數的sizeof結果為8。
char* pc = "abc";
int* pi;
string* ps;
char** ppc = &pc;
void (*pf)();// 函式指標
sizeof( pc ); // 結果為4
sizeof( pi ); // 結果為4
sizeof( ps ); // 結果為4
sizeof( ppc ); // 結果為4
sizeof( pf );// 結果為4
指標變數的sizeof值與指標所指的物件沒有任何關係,正是由於所有的指標變數所佔記憶體大小相等,所以mfc訊息處理函式使用兩個引數wparam、lparam就能傳遞各種複雜的訊息結構(使用指向結構體的指標)。
6. 陣列的sizeof
陣列的sizeof值等於陣列所占用的記憶體位元組數,如:
char a1 = "abc";
int a2[3];
sizeof( a1 ); // 結果為4,字串末尾還存在乙個null終止符
sizeof( a2 ); // 結果為3*4=12(依賴於int)
一些朋友剛開始時把sizeof當作了求陣列元素的個數,現在,你應該知道這是不對的,那麼應該怎麼求陣列元素的個數呢?easy,通常有下面兩種寫法:
int c1 = sizeof( a1 ) / sizeof( char ); // 總長度/單個元素的長度
int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 總長度/第乙個元素的長度
寫到這裡,提一問,下面的c3,c4值應該是多少呢?
void foo3(char a3[3])
void foo4(char a4)
也許當你試圖回答c4的值時已經意識到c3答錯了,是的,c3!=3。這裡函式引數a3已不再是陣列型別,而是蛻變成指標,相當於char* a3,為什麼?仔細想想就不難明白,我們呼叫函式foo1時,程式會在棧上分配乙個大小為3的陣列嗎?不會!陣列是「傳址」的,呼叫者只需將實參的位址傳遞過去,所以a3自然為指標型別(char*),c3的值也就為4。
8. 含位域結構體的sizeof
前面已經說過,位域成員不能單獨被取sizeof值,我們這裡要討論的是含有位域的結構體的sizeof,只是考慮到其特殊性而將其專門列了出來。
c99規定int、unsigned int和bool可以作為位域型別,但編譯器幾乎都對此作了擴充套件,允許其它型別型別的存在。
使用位域的主要目的是壓縮儲存,其大致規則為:
1) 如果相鄰位域字段的型別相同,且其位寬之和小於型別的sizeof大小,則後面的字段將緊鄰前乙個字段儲存,直到不能容納為止;
2) 如果相鄰位域字段的型別相同,但其位寬之和大於型別的sizeof大小,則後面的字段將從新的儲存單元開始,其偏移量為其型別大小的整數倍;
3) 如果相鄰的位域字段的型別不同,則各編譯器的具體實現有差異,vc6採取不壓縮方式,dev-c++採取壓縮方式;
4) 如果位域字段之間穿插著非位域字段,則不進行壓縮;
5) 整個結構體的總大小為最寬基本型別成員大小的整數倍。
還是讓我們來看看例子。
示例1:
struct bf1
;其記憶體布局為:
|_f1__|__f2__|_|____f3___|____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
位域型別為char,第1個位元組僅能容納下f1和f2,所以f2被壓縮到第1個位元組中,而f3只能從下乙個位元組開始。因此sizeof(bf1)的結果為2。
示例2:
struct bf2
;由於相鄰位域型別不同,在vc6中其sizeof為6,在dev-c++中為2。
示例3:
struct bf3
;非位域字段穿插在其中,不會產生壓縮,在vc6和dev-c++中得到的大小均為3。
2023年終盤點 終章篇
這期間公司進行了總結 述職 面談等一系列年終流程,去年的篇章終於將翻過去了,這篇的總結是將是2010的終章。2010年仍然是波瀾不驚,做的事情仍然是默默無聞,但經過一系列的總結,發現之前辛勤而默默的耕耘都是量的積累。初中就學 量變必然引起質變 確實,現在慢慢開始顯出質的變化了。思維能力。簡單地說就是...
事件基礎 終
預設行為 什麼是預設行為 l阻止表單預設行為 stop from 普通寫法 return false oncontextmenu 瀏覽器右擊屬性 例子1.遮蔽右鍵選單 彈出自定義右鍵選單 out right of 例子2.只能輸入數字的輸入框 keydown keyup事件的區別 number on...
sizeof 陣列名 和sizeof 指標
在做這道題時 32位環境下,int p new int 10 請問sizeof p 的值為 a 4 b 10 c 40 d 8 我以為正確答案為c,int型別為32位,佔四個位元組,10個自然就是40了,結果正確答案為a,只是指標p佔的空間。因此寫段 測試一下 cpp view plain copy...