內存總結之返回對象佔用字節數操作符sizeof

@著作權歸作者所有:來自CSDN博客作者大鬍子的艾娃的原創作品,如需轉載,請註明出處https://blog.csdn.net/qq_43148810,否則將追究法律責任。
如有錯誤的地方歡迎指正,謝謝!

申明:sizeof() 是一個判斷數據類型或者表達式長度的運算符。sizeof() 的處理都是在編譯階段進行。其作用就是返回一個對象或者類型所佔的內存字節數。

一:sizeof求基本數據類型所佔的內存字節數關係表。
大鬍子的艾娃
但是sizeof(void)是非法的,沒有人會定義一個void變量,void真正發揮的作用在於:對函數返回的限定;對函數參數的限定。
Visual Studio 2017上void a;//顯示不允許使用不完整的類型,並且會報錯C2182,非法使用"void"類型。

二、sizeof求指針所佔的內存字節數
1、32位系統爲4,64位系統則爲8。
2、所有的指針變量所佔內存大小相等,因爲指針變量的sizeof值與指針所指的對象沒有任何關係。

三、sizeof求enum枚舉類型所佔的內存字節數
1、枚舉類型,本質上是一組常數的集合體,只是這些常數有各自的命名。枚舉類型,是一種用戶自定義數據類型。
2、枚舉變量,由枚舉類型定義的變量。枚舉變量的大小,即枚舉類型所佔內存的大小。由於枚舉變量的賦值,一次只能存放枚舉結構中的某個常數。所以枚舉變量的大小,實質是常數所佔內存空間的大小,枚舉類型所佔內存大小也是這樣。

四、sizeof求array數組所佔的內存字節數
1、數組的sizeof值等於數組所佔用的內存字節數==元素類型大小*元素個數。
2、當字符數組表示字符串時,其sizeof值將’/0’計算進去。
3、數組名作爲實參傳入函數時,會自動轉化爲指針類型,所以其sizeof值相當於指針的sizeof值。

五、sizeof求union聯合體所佔的內存字節數
1、聯合體union性質
a、聯合體所有成員變量共享內存,相對於聯合體首地址偏移量都爲0。
b、同一時間只能存儲1個被選擇的變量,對其他成員變量賦值會覆蓋原變量。

2.聯合體大小計算準則
a、聯合體大小要至少能容納最大的成員變量。
b、複合數據類型,如union、struct、class的對齊方式爲成員中最大的成員對齊方式。(數組可以理解爲多個相同成員的集合)。

3、對齊是可以更改的,使用#pragma pack(x)可以改變編譯器的對其方式。

六、sizeof求struct結構體所佔的內存字節數
1、結構體的sizeof涉及到字節對齊問題。
爲什麼需要字節對齊?計算機組成原理教導我們這樣有助於加快計算機的取數速度,否則就得多花指令週期了。爲此,編譯器默認會對結構體進行處理(實際上其它地方的數據變量也是如此),讓寬度爲2的基本數據類型(short等)都位於能被2整除的地址上,讓寬度爲4的基本數據類型(int等)都位於能被4整除的地址上,依次類推。這樣,兩個數中間就可能需要加入填充字節,所以整個結構體的sizeof值就增長了。

2、字節對齊的細節和編譯器的實現相關,但一般而言,滿足三個準則:
a、結構體變量的首地址能夠被其最寬基本類型成員的大小所整除。
b結構體的每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要,編譯器會在成員之間加上填充字節(internal adding)。
c、結構體的總大小爲結構體最寬基本類型成員大小的整數倍,如有需要,編譯器會在最末一個成員後加上填充字節(trailing padding)。

注意:空結構體(不含數據成員)的sizeof值爲1。試想一個“不佔空間“的變量如何被取地址、兩個不同的“空結構體”變量又如何得以區分呢,於是,“空結構體”變量也得被存儲,這樣編譯器也就只能爲其分配一個字節的空間用於佔位了。

d、C99規定int、unsigned int和bool可以作爲位域類型,但編譯器幾乎都對此作了擴展,允許其它類型類型的存在。使用位域的主要目的是壓縮存儲,其大致規則爲:
(1)如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則後面的字段將緊鄰前一個字段存儲,直到不能容納爲止
(2)如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則後面的字段將從新的存儲單元開始,其偏移量爲其類型大小的整數倍。
(3)如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6採取不壓縮方式,Dev-C++採取壓縮方式。
(4)如果位域字段之間穿插着非位域字段,則不進行壓縮。
(5)整個結構體的總大小爲最寬基本類型成員大小的整數倍。
還是讓我們來看看例子。
示例1:
struct BF1{char f1:3;char f2:4;char f3:5;};
其內存佈局爲:
大鬍子的艾娃
位域類型爲char,第1個字節僅能容納下f1和f2,所以f2被壓縮到第1個字節中,而f3只能從下一個字節開始。因此sizeof(BF1)的結果爲2。
示例2:
struct BF2{char f1:3;short f2:4;char f3:5;};
由於相鄰位域類型不同,在VC6中其sizeof爲3,在Dev-C++中爲2。
示例3:
struct BF3{char f1:3;char f2;char f3:5;};
非位域字段穿插在其中,不會產生壓縮,在VC6和Dev-C++中得到的大小均爲3。

七、sizeof求class類的對象所佔的內存字節數
1、c++中類所佔的大小計算涉及到虛函數成員,靜態成員,虛繼承,多繼承以及空類等。

2、聲明的類只是一種類型定義,它本身是沒有大小可言的。這裏指的類的大小,其實指的是類的對象所佔的大小。

3、關於類/對象大小的計算
a、首先,類大小的計算遵循結構體的對齊原則
b、類的大小與普通數據成員有關,與成員函數和靜態成員無關。
d、即普通成員函數,靜態成員函數,靜態數據成員,靜態常量數據成員均對類的大小無影響。
e、虛函數對類的大小有影響,是因爲虛函數表指針帶來的影響。
f、虛繼承對類的大小有影響,是因爲虛基表指針帶來的影響
g、空類的大小是一個特殊情況,空類的大小爲1

4、sizeof求STL中的string類的對象所佔的內存字節數
Visual Studio中普遍是28字節,VC 6.0算出來的是16字節,有些書上是4字節。

提示:capacity()容量默認容量大小(Visual Studio2015),少於15個,申請15個容量(至少申請15個),以後容量不足就增加當前的1/3大小,直到容量足夠。VC++6.0 是至少申請31個空間,以後每次增加32個。
容量是指string對象不改變存儲地址所能容納最大字符串數量,>=string.size()求得數。
STL中的vector,list,deque,map,set等自己總結。

八、sizeof與strlen的區別
1、strlen(char*)函數求的是字符串的實際長度,直到遇到第一個’\0’,然後就返回計數值,且不包括’\0’。而sizeof()函數返回的是變量聲明後所佔的內存數,不是實際長度。
2、sizeof是算符,strlen是函數。
3、sizeof可以用類型做參數,strlen只能用char*做參數,且必須是以’’\0’'結尾的;sizeof還可以用函數做參數。
4、數組做sizeof的參數不退化,傳遞給strlen就退化爲指針了。
5、大部分編譯程序在編譯的時候就把sizeof計算過了是類型或是變量的長度,結果可以sizeof(x)結果可以用來定義數組維數,strlen的結果要在運行的時候才能計算出來,是用來計算字符串的長度,不是類型佔內存的大小。

九、其他提示拓展
1、sizeof 無法獲取動態分配的內存大小,即使用malloc/new動態的分配內存,無法使用sizeof獲取其大小。
2、vs2017中“ char* str = “1234asd56”; ” 會報錯:"const char*"類型的值不能用於初始化"char*"類型的實體,但是VS2015及其以前的版本都不會報錯警告之類的。

本文只是用sizeof帶出C++內存部分的知識,作爲一名優秀的C++程序員,應該要非常清楚內存相關的知識,本文就算是拋磚引玉,希望大家在這方面深入研究。

更多內容請關注個人博客:https://blog.csdn.net/qq_43148810

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章