(引)sizeof終極無惑

2021-04-16 19:46:47 字數 4018 閱讀 7082

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...