sizeof
strlen("\0")與sizeof("\0")
strlen("\0") = 0
,
sizeof("\0") = 2
。
strlen
strlen用來計算字元串的長度,它從記憶體的某個位置開始掃描,直到碰到第一個字元串結束符’\0’為止,然後傳回計數器值
sizeof
sizeof是C語言的關鍵字,它以位元組的形式給出了其操作數的存儲大小,操作數可以是一個表達式或括在括号内的類型名,操作數的存儲大小由操作數的類型決定
strlen與sizeof的差別
- sizeof是運算符(sizeof既是關鍵字,也是運算符,但不是函數),而strlen是函數。sizeof後如果是類型,則必須加括弧,如果是變量名,則可以不加括弧
- sizeof運算符的結果類型是size_t,它在頭檔案中typedef為unsigned int類型。該類型保證能夠容納實作所建立的最大對象的位元組大小
- sizeof可以用類型作為參數,strlen隻能用char*作為參數,而且必須是以’\0’結尾的。sizeof還可以以函數作為參數,如
,則int g();
的值等于sizeof(int)的值,在32位計算機下,該值為4sizeof(g())
- 大部分編譯程式的sizeof都是在編譯的時候計算的,是以可以通過
來定義數組維數。而strlen則是在運作期計算的,用來計算字元串的實際長度,不是類型占記憶體的大小。sizeof(x)
對于結構體,為什麼sizeof傳回的值一般大于期望值
struct是一種複合資料類型,其構成元素既可以是基本資料類型,如int、double、float、short、char等,也可以是複合資料類型,如數組、struct、union等資料單元
一般而言,struct的sizeof是所有成員對齊後長度相加,而union的sizeof是取最大的成員長度
位元組對齊
位元組對齊也稱為位元組填充,它是C++編譯器的一種技術手段,主要是為了在空間與複雜度上達到平衡。簡單地講,是為了在可接受的空間浪費的前提下,盡可能地提高對相同運算過程的最少(快)處理。位元組對齊的作用不僅是便于CPU的快速通路,使CPU的性能達到最佳,而且可以有效地節省存儲空間。
例如,32位計算機的資料傳輸是4位元組,64位計算機的資料傳輸是8位元組,這樣,struct在預設情況下,編譯器會對struct的結構進行(32位機)4的倍數或(64位機)8的倍數的資料對齊。對于32位機來說,4位元組的對齊能夠使CPU通路速度提高,如一個long類型的變量,如果跨越了4位元組邊界存儲,那麼CPU要讀取兩次,這樣效率就低了。但需要注意的是,如果在32位機中使用1位元組或者2位元組對齊,不僅不會提高效率,反而會使通路速度降低。
修改對齊條件
在預設情況下,編譯器為每一個變量或資料單元按其自然對齊條件配置設定空間。但是可以通過下面的方法來改變預設的對齊條件
- 使用僞指令
,編譯器将按照n個位元組對齊#pragma pack(n)
- 使用僞指令
,取消自定義位元組對齊方式#pragma pack()
-
,讓所作用的結構成員對齊在n位元組自然邊界上。如果結構中有成員的長度大于n,則按照最大成員的長度來對齊_attribute((aligned(n))
-
,取消結構在編譯過程中的優化對齊,按照實際占用位元組數進行對齊_attribute((packed))
位元組對齊的準則
位元組對齊的細節和編譯器實作相關,但一般而言,滿足以下準則:
- 結構體變量的首位址能夠被其最寬基本類型成員的大小所整除
- 結構體每個成員相對于結構體首位址的偏移量(offset)都是成員大小的整數倍。如有需要,編譯器會在成員之間加上填充位元組
- 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充位元組
其中的基本類型即char、short、int、float、double這樣的内置資料類型,這裡說的“資料寬度”就是指其sizeof的大小
由于結構體的成員可以是複合類型,如果一個結構體中包含另外一個結構體成員,那麼此時最寬基本成員不是該結構體成員,而是取其基本類型的最寬值。但在确定複合類型成員的偏移位置時,則是将複合類型作為整體看待,即複雜類型(如結構)的預設對齊方式是它最長的成員的對齊方式,這樣在成員是複雜類型時,可以最小化長度,達到程式優化的目的
指針進行強制類型轉換後與位址進行加法運算
假設在32位機器上,在對齊為4情況下,
sizeof(long)
的結果為4位元組,
sizeof(char*)
的結果為4位元組,
sizeof(short int)
的結果與
sizeof(short)
的結果都為2位元組,
sizeof(char)
的結果為1位元組,
sizeof(int)
的結果為4位元組,由于32位機器上是4位元組對齊,以如下結構體為例:
struct A
{
long num;
char *name;
short int data;
char ha;
short ba[5];
}*p;
在32位機器下,
sizeof(struct A) = 4 + 4 + 2 + 2 + 1 + 3 + 2*5 + 2 = 24
位元組
當
p=0x100000
,那麼
p + 0x200 = 0x1000000 + 0x200*24
指針加法,加出來的是指針所指類型的位元組長度的整數倍,就是p偏移
sizeof(*p)*0x200
而
(ulong)p + 0x200 = 0x1000000 + 0x200
經過
ulong
後,已經不再是指針加法,而變成一個數值加法了
另外
(char*)p + 0x200 = 0x1000000 + 0x200*sizeof(char)
結果類型是
char*