sizeof 那點兒事兒

2021-09-22 00:25:24 字數 3404 閱讀 6650

c++,用了許久發現我對你的了解還真的不夠,至少可以這樣來評價自己的了解:剛剛接觸皮毛!所以我打算把c++在系統的複習,或者說重新學習一下。一下我的測試**都是在vc++ 6.0和32位作業系統下做的測試,參考《c++國際標準1998》和《inside the c++ object model》。

一,由sizeof()函式引發的故事:

用sizeof()來計算乙個空類的大小,**如下:

class classsize

;int main()

void func2(char a4)

也許當你試圖回答c4的值時已經意識到c3答錯了,是的,c3!=3。這裡函式引數a3已不再是陣列型別,而是蛻變成指標,相當於char* a3,為什麼仔細想想就不難明白,我們呼叫函式func時,程式會在棧上分配乙個大小為3的陣列嗎?不會!陣列是「傳址」的,呼叫者只需將實參的位址傳遞過去,所以a3自然為指標型別(char*),c3的值也就為4。

4,結構體的sizeof

struct mystruct

;//結果為16

為上面的結構分配空間的時候,vc根據成員變數出現的順序和對齊方式,先為第乙個成員dda分配空間,其起始位址跟結構的起始位址相同(剛好偏移量0剛好為sizeof(double)的倍數),該成員變數占用sizeof(double)=8個位元組;接下來為第二個成員strdda分配空間,這時下乙個可以分配的位址對於結構的起始位址的偏移量為8,是sizeof(char)的倍數,所以把strdda存放在偏移量為8的地方滿足對齊方式,該成員變數占用sizeof(char)=1個位元組;接下來為第三個成員ntype分配空間,這時下乙個可以分配的位址對於結構的起始位址的偏移量為9,不是sizeof(int)=4的倍數,為了滿足對齊方式對偏移量的約束問題,vc自動填充3個位元組(這三個位元組沒有放什麼東),這時下乙個可以分配的位址對於結構的起始位址的偏移量為12,剛好是sizeof(int)=4的倍數,所以把ntype存放在偏移量為12的地方,該成員變數占用sizeof(int)=4個位元組;這時整個結構的成員變數已經都分配了空間,總的占用的空間大小為:8+1+3+4=16,剛好為結構的位元組邊界數(即結構中占用最大空間的型別所占用的位元組數sizeof(double)=8)的倍數,所以沒有空缺的位元組需要填充。所以整個結構的大小為:sizeof(mystruct)=8+1+3+4=16,其中有3個位元組是vc自動填充的,沒有放任何有意義的東西。下面這個結構呢?留給讀者自己去測試吧:

struct mystruct

;5,含位域結構體的sizeof

struct data

;其記憶體布局為:

|_f1__|___f2__|_|____f3___|_____|

|_|_ |_|_|_ |_|_|_|_|_|_| _| _|_|_ |_|

0       3             7  8              13       16

位域型別為char,第1個位元組僅能容納下f1和f2,所以f2被壓縮到第1個位元組中,而f3只能從下乙個位元組開始。因此sizeof(data)的結果為2。

6,含有聯合體的結構體的sizeof

struct stru1

;struct stru1* next;                //指標佔4

};//這樣是8+4=12個位元組

struct stru1

;struct stru1* next;                        

};//這樣是8+4+4=16個位元組

看著有點迷糊吧,不要著急,我們慢慢來分析.首先我們再溫習一下什麼是聯合:聯合表示幾個變數公用乙個記憶體位置, 在不同的時間儲存不同的資料型別 和不同長度的變數;當乙個聯合被說明時, 編譯程式自動地產生乙個變數, 其長度為聯合中最大的變數長度。這下或許你有點明白了,不過我們再來看看下面的例子,你就會深刻理解了:

union abc

;  用上面說明的聯合定義乙個名為lgc的聯合變數, 可寫成: union abc lgc,現在編譯器就為lgc分配了4個位元組的記憶體,因為最大為int.如果你覺得還不明白,那你去試試把第乙個結構體改為:

struct stru1

;union a x;

struct stru1* next;                

};//這樣是8+4+4=16個位元組

7,結構體體含有結構體的sizeof

struct stru1

;struct stru2

;cout8,帶有#pragma pack的sizeof

它是用來調整結構體對齊方式的,不同編譯器名稱和用法略有不同,vc6中通過#pragma pack實現,也可以直接修改/zp編譯開關。#pragma pack的基本用法為:#pragma pack( n ),n為位元組對齊數,其取值為1、2、4、8、16,預設是8,如果這個值比結構體成員的sizeof值小,那麼該成員的偏移量應該以此值為準,即是說,結構體成員的偏移量應該取二者的最小值,再看示例:

#pragma pack(push) // 將當前pack設定壓棧儲存

#pragma pack(2)// 必須在結構體定義之前使用

struct stru1

;struct stru2

;#pragma pack(pop) // 恢復先前的pack設定

計算sizeof(s1)時,min(2, sizeof(i))的值為2,所以i的偏移量為2,加上sizeof(i)等於6,能夠被2整除,所以整個s1的大小為6。同樣,對於sizeof(s3),s的偏移量為2,c2的偏移量為8,加上sizeof(c2)等於9,不能被2整除,新增乙個填充位元組,所以sizeof(s3)等於10。

9,空結構體或者空類的sizeof

struct s5 ;

sizeof( s5 ); // 結果為1

class c1;

sizeof( c1); // 結果為1

為什麼?隨便就推薦一本書吧:inside the c++ object model,讀者自己去找答案吧,絕對有幫助.

10,類的sizeof

最後回到我們開始的地方,類的sizeof值等於類中成員變數所占用的記憶體位元組數。如:

class a

;int main(void)

輸出結果為12(我的機器上sizeof(float)值為4,位元組對其前面已經講過)。不過需要注意的是,如果類中存在靜態成員變數,結果又會是什麼樣子呢?

class a

;int main()

結果仍然是12.因為在程式編譯期間,就已經為static變數在靜態儲存區域分配了記憶體空間,並且這塊內存在程式的整個執行期間都存在。而每次宣告了類a的乙個物件的時候,為該物件在堆上,根據物件的大小分配記憶體。如果類a中包含成員函式,那麼又會是怎樣的情況呢?看下面的例子:

class a

};int main()

結果仍為12.因為只有非靜態類成員變數在新生成乙個object的時候才需要自己的副本。所以每個非靜態成員變數在生成新object需要記憶體,而function是不需要的。

sizeof 那點兒事兒

c 用了許久發現我對你的了解還真的不夠,至少可以這樣來評價自己的了解 剛剛接 觸皮毛 所以我打算把c 在系統的複習,或者說重新學習一下。一下我的測試 都是在vc 6.0和32位作業系統下做的測試,參考 c 國際標準1998 和 inside the c object model 一,由sizeof ...

VIM那點兒事兒

一年之前接觸的vim,立馬被傳說的高效率吸引去了,於是大把研究,讀了n久英文教程 後來還是那個水平。知道這幾天又受不了傳統的編輯器,重新收拾起vim,碰見幾個問題,解決。日誌留念。起因是windows下的vim各種bug,如map時無效 用netrw是變成下一行 等很奇異的問題。後來發現把vimrc...

python wraps那點兒事兒

乙個需求的實現 當前,我們有這麼乙個小的需求 通過裝飾器來計算函式執行的時間 計算出這個函式的執行時長 def add x,y add timeit add time.sleep 1 this is add return x y 裝飾器實現 import time import datetime f...