C 程式設計/stdint.h
stdint.h 是 標頭檔案,它包含在 C 標準庫 中,並於 C99 標準庫 的 7.18 節中引入,允許程式設計師透過提供一組型別定義來編寫更可移植的程式碼,這些型別定義指定了精確寬度整數型別,以及使用宏[1] 定義的每個型別的允許最小值和最大值。此標頭檔案對於嵌入式程式設計尤其有用,嵌入式程式設計通常涉及對特定硬體 I/O 暫存器的相當多的操作,這些暫存器需要具有固定寬度、特定位置和精確對齊的整數資料。stdint.h(對於 C 或 C++) 和 cstdint(對於 C++) 可以下載或快速建立,如果它們沒有提供的話。
精確寬度整數型別的命名約定為 intN_t 用於 帶符號 int,uintN_t 用於 無符號 int [1] 。例如,int8_t 和 uint64_t 可以與定義它們各自範圍的 INT8_MIN 到 INT8_MAX 和 0(零)到 UINT64_MAX 宣告在一起;同樣使用類似但大寫字母的命名約定。此外,stdint.h 還定義了能夠容納物件指標的整數型別的限制,例如 UINTPTR_MAX,其值取決於處理器及其地址範圍[1]。
精確寬度型別及其相應的範圍僅在該特定編譯器/處理器存在的情況下才會包含在該標頭檔案中。請注意,即使在同一處理器上,兩個不同的編譯器實現也可能不同。使用 #if 或 #ifdef 將允許透過使用編譯器的預處理器包含或排除型別,以便為編譯器及其處理器目標選擇正確的精確寬度集。
相關的包含檔案 <limits.h> 提供了通用整數變數類型範圍限制的宏值。在 C 中,<limits.h> 已經包含在 <stdint.h> 中,但與 <stdint.h> 不同的是,它與實現無關;<limits.h> 中定義的所有最大和最小整數值都是編譯器實現特定的。例如,生成 32 位可執行檔案的編譯器將定義 LONG_MIN 為 −2,147,483,648 [−231],但對於 64 位處理器目標,LONG_MIN 可以是 −9,223,372,036,854,775,808 [−263]。
C 標準有一個“對應整數型別”的概念。非正式地說,這意味著對於任何整數型別 T
typedef signed T A;
typedef unsigned T B;
型別 A 和型別 B 被稱為對應整數型別(注意:typedef 不會建立新的型別,它建立了一個新的識別符號作為給定型別的同義詞)。這很重要,有兩個原因
- 對應型別對別名和型別雙關語友好
- 對應型別具有類似的物件表示
這兩者的結合需要像這樣的程式碼
A a = 1;
B b = 1;
*(B*)&a = 0;
*(A*)&b = 0;
透過標準具有定義的行為(而不是在一般情況下是未定義的)。關於你能將此推到多遠,有很多注意事項,因此閱讀 C 標準以瞭解什麼是合法或不合法非常重要(這部分內容主要涉及填充位和超出範圍的表示)。
C99 標準闡述了值表示和物件表示之間的區別。
整數的物件表示由 0 個或多個填充位、1 個或多個值位[1] 以及 0 個或 1 個符號位(這不算作值位)組成,具體取決於整數型別的符號。
值表示是整數的概念表示。值表示忽略任何填充位,並對位進行(可能的)重新排列,以便整數按順序從最高有效值位到最低有效值位排序。大多數程式設計師處理此表示,因為它允許他們透過僅處理 −0 和超出範圍的值來輕鬆地編寫可移植的程式碼,而不是同時處理這兩種值,以及如果他們選擇直接處理物件表示,則還會處理棘手的別名規則和陷阱表示。
C 標準僅允許編譯器編寫器指定的三個有符號整數表示
- 符號和大小
- 反碼
- 補碼(最廣泛使用)
型別 <something>_t 和 u<something>_t 必須是對應的有符號和無符號整數型別。對於標記為可選的型別,實現必須同時定義 <something>_t 和 u<something>_t,或者兩者都不定義。這些型別的限制應使用類似於下面描述的格式使用宏定義。
如果一個型別是 [u]<something>N_t 的形式(或類似地用於預處理器定義),N 必須是一個正十進位制整數,沒有前導 0。
這些是 intN_t 和 uintN_t 的形式。兩種型別都必須由正好 N 位表示,沒有填充位。intN_t 必須被編碼為補碼有符號整數,而 uintN_t 則被編碼為無符號整數。這些型別是可選的,除非實現支援寬度為 8、16、32 或 64 的型別,那麼它應將它們型別定義為具有對應 N 的對應型別。任何其他 N 都是可選的[1] 。
| 說明符 | 簽名 | 位 | 位元組 | 最小值 | 最大值 |
|---|---|---|---|---|---|
int8_t
|
帶符號 | 8 | 1 | −27 等於 −128 | 27 − 1 等於 127 |
uint8_t
|
無符號 | 8 | 1 | 0 | 28 − 1 等於 255 |
int16_t
|
帶符號 | 16 | 2 | −215 等於 −32,768 | 215 − 1 等於 32,767 |
uint16_t
|
無符號 | 16 | 2 | 0 | 216 − 1 等於 65,535 |
int32_t
|
帶符號 | 32 | 4 | −231 等於 −2,147,483,648 | 231 − 1 等於 2,147,483,647 |
uint32_t
|
無符號 | 32 | 4 | 0 | 232 − 1 等於 4,294,967,295 |
int64_t
|
帶符號 | 64 | 8 | −263 等於 −9,223,372,036,854,775,808 | 263 − 1 等於 9,223,372,036,854,775,807 |
uint64_t
|
無符號 | 64 | 8 | 0 | 264 − 1 等於 18,446,744,073,709,551,615 |
這些型別的限制使用以下格式的宏定義
INTN_MAX是 intN_t 的帶符號版本的最大值 (2N−1 − 1)。INTN_MIN是 intN_t 的帶符號版本的最小值 (−2N−1)。UINTN_MAX是 uintN_t 的無符號版本的最大值 (2N – 1)。
這些型別的格式為 int_leastN_t 和 uint_leastN_t。int_leastN_t 是一個有符號整數,uint_leastN_t 是一個無符號整數[1]。
標準要求這些型別至少包含 N 個位,並且沒有比它們更小的具有相同符號的型別包含 N 個或更多位。例如,如果一個系統只提供 uint32_t 和 uint64_t,那麼 uint_least16_t 必須等同於 uint32_t。
實現必須為以下 N 定義這些型別:8、16、32、64。其他任何 N 都是可選的。
這些型別的限制使用以下格式的宏定義
INT_LEASTN_MAX是int_leastN_t有符號版本的最大值(2N−1 − 1 或更大)。INT_LEASTN_MIN是int_leastN_t有符號版本的最小值(−2N−1 + 1 或更小)。UINT_LEASTN_MAX是uint_leastN_t無符號版本的最大值(2N − 1 或更大)。
stdint.h 還應該定義宏,用於轉換常量十進位制、八進位制或十六進位制值,這些值保證適用於相應的型別,並且可以使用 #if
INTN_C(value)將被替換為適合int_leastN_t的值。例如,如果int_least64_t被 "typedef" 為signed long long int,那麼INT64_C(123)將對應於123LL。UINTN_C(value)將被替換為適合uint_leastN_t的值。
這些型別的格式為 int_fastN_t 和 uint_fastN_t。
標準沒有對這些型別進行任何強制要求,除了它們的寬度必須大於或等於 N 之外。它還將如何定義 "快速" 整數型別留給實現者決定。
實現必須為以下 N 定義這些型別:8、16、32、64[2]。
這些型別的限制使用以下格式的宏定義
INT_FASTN_MAX是int_fastN_t有符號版本的最大值(2N−1 − 1 或更大)。INT_FASTN_MIN是int_fastN_t有符號版本的最小值(−2N−1 + 1 或更小)。UINT_FASTN_MAX是uint_fastN_t無符號版本的最大值(2N − 1 或更大)[1]。
intptr_t 和 uintptr_t 分別是有符號和無符號整數,保證能夠容納指標的值。這兩個型別是可選的。
這些型別的限制透過以下宏定義:
INTPTR_MIN是intptr_t的最小值(−32,767 [−215 + 1] 或更小)。INTPTR_MAX是intptr_t的最大值(32,767 [215 − 1] 或更大)。UINTPTR_MAX是uintptr_t的最大值(65,535 [216 − 1] 或更大)[3]。
intmax_t 和 uintmax_t 是支援的最大寬度的有符號和無符號整數。換句話說,它們是限制最大的整數型別。
這些型別的限制使用以下格式的宏定義
INTMAX_MAX是intmax_t有符號版本的最大值(9,223,372,036,854,775,807 [263 − 1] 或更大)。INTMAX_MIN是intmax_t有符號版本的最小值(−9,223,372,036,854,775,807 [−263 + 1] 或更小)。UINTMAX_MAX是uintmax_t無符號版本的最大值(18,446,744,073,709,551,615 [264 − 1] 或更大)。
還定義了用於轉換常量十進位制、八進位制或十六進位制值的宏,這些值將適合相應的型別。
INTMAX_C(value)將被替換為適合intmax_t的值。UINTMAX_C(value)將被替換為適合uintmax_t的值[1]。
PTRDIFF_MIN是ptrdiff_t的最小值。PTRDIFF_MAX是ptrdiff_t的最大值。SIZE_MAX是size_t的最大值(216 − 1 或更大)。WCHAR_MIN是wchar_t的最小值。WCHAR_MAX是wchar_t的最大值。WINT_MIN是wint_t的最小值。WINT_MAX是wint_t的最大值。SIG_ATOMIC_MIN是sig_atomic_t的最小值。SIG_ATOMIC_MAX是sig_atomic_t的最大值。
- 一些(不符合標準的)實現將 C99 支援附加到 C89 執行時庫之上。[需要引用] 這樣做的結果之一是,新的
printf和scanf指定符不被識別,可能會導致一些未定義的行為。解決此問題的典型方法是- 最常見(也是最錯誤)的方法是使用
long或unsigned long型別作為中間步驟,並將這些型別傳遞給printf或scanf。對於小於 32 位的精確、最小和快速整數型別,這種方法可以正常工作,但在ptrdiff_t和size_t以及大於 32 位的型別(通常在使用 32 位long和 64 位指標的平臺上)可能會出現問題。 - 不直接使用
scanf,而是手動讀入緩衝區,呼叫strto<i|u>max,然後將其轉換為所需型別。不過,這不能幫助列印整數。 - 使用與 C99 相容的第三方
printf和scanf庫。 - 使用 C99 標準列印格式指定符。例如 PRId64。這些指定符在 inttypes.h 中宣告。
- 最常見(也是最錯誤)的方法是使用
- 整數等級和對應整數型別的規則可能會迫使實現者在不支援整數型別、做出糟糕的妥協或以不符合標準的方式支援整數型別之間做出兩難選擇。
- 例如,有些機器要麼對極大的有符號整數暫存器提供特殊支援,要麼對極大的無符號整數暫存器提供特殊支援,而沒有對其他型別提供支援。[需要引用] 實現可以選擇不將此功能暴露給 C 實現,合成一個緩慢的型別作為對應的整數型別,合成一個奇怪的對應整數型別,或者將整數暴露給程式設計師,而不將其設定為
[u]intmax_t型別或合成一個對應的整數型別。
- 例如,有些機器要麼對極大的有符號整數暫存器提供特殊支援,要麼對極大的無符號整數暫存器提供特殊支援,而沒有對其他型別提供支援。[需要引用] 實現可以選擇不將此功能暴露給 C 實現,合成一個緩慢的型別作為對應的整數型別,合成一個奇怪的對應整數型別,或者將整數暴露給程式設計師,而不將其設定為
[u]intN_t型別是在希望擁有保證的二進位制補碼整數型別和希望擁有保證的沒有填充位的型別之間的折衷方案(與更細粒度的方案相比,後者將定義更多型別)。由於[u]intN_t型別採取 "全有或全無" 的方式,因此根據它們是否關心速度、程式設計師的便利性或標準符合性,實現可能不得不玩上面描述的同類遊戲。
- ↑ a b c d e f g h 從技術上講,它實際上允許 0 個或多個值位,但你構建它的唯一方法是使用一個有符號整數的單位元位域
- ↑ http://www.tuxgraphics.org/common/src2/article09043/avr-libc-user-manual-1.6.4/group__avr__stdint.html
- ↑ http://linux.die.net/man/3/intptr_t
- : 整數型別 – 基礎定義參考,單一UNIX®規範,第7版來自開放組
由於stdint.h沒有隨舊版本的C++編譯器和Visual Studio C++產品(早於Visual Studio 2010)一起提供,因此可以使用第三方實現
- pstdint.h – 來自Paul Hsieh的跨平臺、免費實現。此實現已在以下編譯器上進行測試,所有編譯器在各自最高設定下均無警告:Borland Turbo C 2.0、WATCOM C/C++ 11.0(16位和32位)、Microsoft Visual C++ 6.0(32位)、Microsoft Visual Studio.net(VC7)、Intel C++ 4.0、GNU gcc v3.3.3。
- msinttypes – 適用於Microsoft Visual Studio的ISO C9x相容stdint.h和inttypes.h可在Google Code上獲得。此實現已在Microsoft Visual Studio 6.0、Microsoft Visual Studio .NET 2003、Microsoft Visual Studio 2005和Microsoft Visual Studio 2008中進行測試。
- boost/cstdint.hpp – 此檔案來自Boost庫,包含stdint.h中的資料型別。使用<boost/cstdint.hpp>的優勢在於它可以在許多平臺上使用。程式碼自然可移植,只要可以使用boost庫,就可以在任何平臺上進行編譯而無需更改。