本文轉載自【微信公眾號:雲深之無跡,ID:TT1827652464】經微信公眾號授權轉載,如需轉載與原文作者聯繫
雖說C語言是一門很成熟的程式語言,但是近些年來也是有所發展的,從早期的C89到後來的C99、C11等新標準,C語言逐步增加了許多好用的功能,例如新標準頭文件「stdint.h」的添加。
如果程式設計師希望寫出可移植的C語言程序,首先最重要的一點是不能假定位寬。C語言標準並沒有明確指定的 short、int、long 等類型的位寬,因此可能在某些平臺 sizeof(int) 等於 2,在其他平臺 sizeof(int) 等於 4,所以如果編寫的C語言代碼假定 sizeof(int) 是一個固定值,顯然就屬於不可移植的代碼。
為了解決這樣的問題,在新標準文件「stdint.h」 之前,程式設計師必須做些額外的工作,以確定C語言代碼運行的平臺的各種數據位寬,這樣的工作著實煩人,稍不留神就會出錯。
「stdint.h」頭文件的添加就是為了便於程式設計師寫出不假定位寬的程序的。其內部通過 typedef 和宏判斷定義了不少好用的整數類型,例如 int8_t 類型表示 8 位的有符號的整數類型,uint32_t 則表示 32 位的無符號的整數類型。類似的,還有 int16_t、int64_t、uint64_t 等類型,都是比較好理解的。
C語言中的「快」類型
不過,如果讀者打開 stdint.h 頭文件,應該能夠看到一些更有趣的類型,如下圖:
可以看出,這些類型被稱作「fast type」,類型名中也有 fast 的字樣(如 int_fast16_t),直譯成中文即「快類型」,那麼它們到底有什麼含義呢?
觀察力敏銳的讀者應該發現了,int_fast16_t 和 int_fast32_t 其實是一樣的,以上圖黃框為例,它們都表示 int 類型,這是怎麼回事呢?int 類型怎麼能同時表示 16 位寬和 32 位寬的整數類型呢?
int 類型當然不能同時表示兩種位寬的整數類型,事實上,int_fastxx_t 類型並不是準確的 xx 位寬類型,它表示不低於 xx 位寬的類型,因此,只要 int 的位寬大於或者等於 32 位,它就能同時表示 int_fast16_t 和 int_fast32_t 類型。
有讀者看到這裡可能會有疑問,如果 int 的位寬等於 32,那麼使用它來表示 16 位寬的 int_fast16_t 整數類型,不是造成資源浪費了嗎?
其實讀者應將注意力放在「fast」一詞上。CPU 從內存取數據一般是逐字取得,這裡的「字」並不是字節的意思,在 32 位主機上,字長常常是 4 個字節,也即 CPU 單次取出數據的最小單位是 4 個字節。
字長也可以理解為 CPU 讀取數據的「步長」。
也就是說,CPU 讀取數據的「步長」是字長(下文以4位元組為例),也就是說假設這次讀取了地址 0~3 的數據,接下來若是希望讀取相鄰的數據,最接近的地址也得是地址 4~7。其實從這裡可以看出,CPU 每次讀取數據的起始地址都是字長的整數倍。
這也是「數據對齊」的原因——為了CPU讀取數據的效率。
如果需要讀取的數據只有一個字節(char 型),那麼顯然,無論該字節放在哪裡,它總是在某個字長段的範圍內的(例如地址 0~3,地址 4~7 內),此時 CPU 一次就能讀取完畢。
如果需要讀取的數據有兩個字節(16bits),情況就不同了——它的地址可能是 3~4,而 CPU 讀取數據的「步長」是 4 個字節,若要讀取該值,CPU 只能先讀取 0~3 字節的數據,再讀取 4~7 字節的數據,最後還需要組合拼湊,才能得到該值。這樣的一系列操作顯然非常低效。
所以 stdint.h 將「快」類型定義為字長的整數倍的意圖就一目了然了,無非就是犧牲一些「空間」換取「時間」。當然了,讀者在使用「快類型」時需要注意:int_fast16_t 並不一定恰好是 16 位寬,它只是不少於 16 位寬的類型。
C語言中的「小」類型
前面提到,int_fastxx_t 類型犧牲了「空間」換取「時間」,如果在某個C語言項目中,「空間」效率並不是特別重要,而「空間」效率卻非常重要,那麼 int_fastxx_t 類型顯然就不合適了。此時可以使用 stdint.h 中定義的 「small type」,也即「小類型」。
int_leastxx_t 系列的數據類型基本上保證了其恰好是 xx 位寬,避免了空間浪費,但是按照前文的分析,「小類型」付出的代價是損失了一部分時間效率。
小結
本文主要討論了C語言新增頭文件「stdint.h」中定義的幾種整數類型,並在此基礎上討論了「時間」效率和「空間」效率的矛盾。事實上,"stdint.h" 頭文件中還定義了其他一些好用的宏,比如整數指針,各個數據類型的最大值和最小值等等,留給讀者自己查看了。
// 詳解下各種類型
https://stackoverflow.com/questions/9239558/what-is-the-difference-between-intxx-t-and-int-fastxx-t
https://stackoverflow.com/questions/tagged/c?tab=votes&page=124&pagesi