天天看點

C++:關于sizeof

關于sizeof

sizeof運算符傳回一條表達式或者一個類型名字所占的位元組數,滿足右結合律,傳回值是一個size_t類型的常量表達式。sizeof 并不會對運算對象進行實際的求值運算。sizeof的計算通常發生在編譯時刻,可以被當作常量表達式來使用,存在兩種表達方式:

sizeof (type);

sizeof expr; 

1)對char或者類型為char的表達式執行sizeof運算,其結果為1;

2)對引用類型進行sizeof操作得到的是被引用對象所占空間的大小;

3)對指針執行sizeof運算得到的是指針本身所占空間的大小;

4)對解引用指針執行sizeof運算得到的是指針所指對象所占空間的大小,其中指針并不一定需要有效;

5)對數組(數組名)執行sizeof操作得到整個數組所占空間的大小;

6)對string或者vector對象執行sizeof操作隻傳回該類型固定部分的大小,不會計算其中元素占用的空間。

一、32/64位系統

32、64位作業系統,不同類型變量對應的位元組數為:(紅色的表示與32位系統不同之處)

char :1個位元組 (32、64位)

指針變量: 、4位元組(32位)、8個位元組 (64位)

short int : 2個位元組 (32、64位)

int: 4個位元組 (32、64位)

unsigned int : 4個位元組 (32、64位)

unsigned long: 8個位元組(32、64位)

long: 4位元組(32位)、8個位元組(32、64位)

long long: 8個位元組(32、64位)

float: 4個位元組 (32、64位)

double: 8個位元組(32、64位)

long double: 8位元組(32位)、16個位元組(位)

二、位元組對齊

計算機存儲系統中以Byte為機關存儲資料,不同資料類型所占的空間不同。計算機為了快速的讀寫資料,預設情況下将資料存放在某個位址的起始位置,如整型資料(int)預設存儲在位址能被4整除的起始位置,字元型資料(char)可以存放在任何位址位置(被1整除),短整型(short)資料存放在位址能被2整除的起始位置。這就是預設位元組對齊的方式。

1、資料類型自身的對齊值

不同系統的對齊值不同。在32位系統中,對于char類型,自身對齊值為位元組;對于short類型,自身對齊值為2位元組;對于int、float類型,自身對齊值為4位元組。

2、結構體或者類的自身對齊值

其成員中自身對齊值最大的那個值,包括是複合類型的成員(如其他結構體)。

3、指定對齊值

#pragma pack(n)

三、常見類型的sizeof

1、基本内置資料類型

基本的資料類型如short 、int、long、float、double等簡單的内置資料類型,由于其所占的記憶體大小和使用的系統有關,是以在不同的系統中取值可能不同,在使用的時候盡量考慮代碼的遺植問題。

2、指針類型的sizeof

指針類型存放的指向一個對象的位址,在32位系統中,位址為4位元組;在64位系統中,位址為8位元組。使用sizeof時不用考慮指針指向的是什麼類型的資料。

3、數組的sizeof

數組的sizeof值就是數組本身所占用的記憶體位元組數。雖然數組名本身也可以轉化為一個指向首元素的指針,但其類型确實數組類型(複合類型),用sizeof 求解時不時求解位址的位元組,大小而是整個數組記憶體的大小。而對于位于函數形參中的數組,它是一個指針類型,而不是數組類型,是以此時的sizeof是按照指針類型來求解的。

4、結構體的sizeof

三個原則:結構體變量的首位址能夠被最大的對齊值所整除;結構體中每個成員相對于首位址的偏移量都是該成員自身對齊值的整數倍;結構體總大小為最大對齊值得整數倍。

是以在計算結構體的sizeof時:先計算各個成員的自身對齊值,取最大的作為結構體的對齊值;依次按順序排放各個成員,成員存放的起始的位置應該是自身對齊值的整數倍,成員間可能存在浪費的記憶體空間;排放完所有成員後,整個結構體的記憶體位元組大小必須是該結構體對齊值的整數倍,不夠也補上。

一旦使用了#pragma pack(n),n為指定過的對齊值,那麼需要取n與計算結構體的對齊值之中較小的那一個作為結構體的對齊值。

空結構體的大小為1.

5、聯合體的sizeof

結構體在記憶體組織上是順序的而聯合體則是重疊式的,各成員共享一段記憶體,是以整個聯合體的sizeof也就是其成員sizeof的最大值。

6、位域的sizeof

1).一個位域的大小可以超過一個位元組,大小不要超過其聲明的類型大小即可:

如:

int name:31;

2).如果相鄰位域的類型相同,且其位寬之和小于等于類型的sizeof大小,則兩位域放入一個字段存儲:

如:

char name1 : 2;

char name2 : 6;

則這2個字段放入一個位元組存儲, sizeof結果為 1.

3).如果相鄰位域的類型相同,且其位寬之和大于類型的sizeof大小,則第二個位段從下一個對齊開始存儲:

如 :

char name1 : 5;

char name2 : 4;

則這2個字段放入兩個位元組存儲,sizeof結果為 2.

4).如果相鄰位域的類型不同,則這多個位段會存儲在類型sizeof大的位段中,如果所有位段大小之和

小于等于最大類型的sizeof,則可以全部裝下,否則,整個位域的存儲空間會以最大類型的sizeof長度

來進行擴充 :

如 :

struct str{

char name1 :1;

int name2 :30;

char name3 :x;

};

當 x = 1時, sizeof(str) = 4;

當 x = 2時, sizeof(str) = 8;

5).如果你要使用位域,你應該很清楚每個字段的大小,進而有序的安排位域的順序,最小化總字段空間:

如 :

struct str{ struct str{

char name1 : 4; char name1 : 4;

char name2 : 5; char name3 : 4;

char name3 : 4; char name2 : 5;

}; };

sizeof(str) = 3; sizeof(str) = 2;

四、sizeof與strlen的差別

1)sizeof是一個操作符(運算符),其結果為size_t 類型,而strlen是一個函數。

2)sizeof可以使用類型名作參數甚至是函數調用作為參數,而strlen隻能使用 char* 類型作為參數且其指向的字元串必須以'\0'結尾。

3)sizeof在編譯的時候計算,可以作為常量表達式;strlen在運作時計算,且計算的字元串的長度而不是記憶體的大小。

繼續閱讀