C++ 固定大小的整數型別

| | 0 Comments| 09:01
Categories:

這篇簡單來記錄一下 C++11 加入、代表特定大小的整數型別(Fixed width integer types)。

一般來說,在 C++ 裡面我們要使用整數型別的變數的時候,大致上會根據數值上的需求,宣告成 charshortintlonglong long;而如果不考慮負數的話,則可以在前面加上 unsigned、變成無號整數。而其他也還有像是 short intsigned short 這類的用法。

但是這邊有一個問題,那就是上面這些型別到底用了多少記憶體

char 由於代表的是字元,一般都是 8bit 沒有太大的問題;而 short 以此類推應該是 16bit,但是 intlonglong long 呢?理論上應該是二進位的形式越來越大,所以是 32、64、128 嗎?但是現在 C++ 真的有 128bit 的整數嗎?當然沒有。

實際上,C++ 的標準裡面針對這些基礎的整數型別,只有定義他們最少要有幾 bit,而並沒有嚴格規範實際上是多少;實際上這些型別要使用多少記憶體、數值範圍多大,是會根據實作而不同的

在《Fundamental types》這篇有列出標準的規範、以及一些實際的狀況;而 Heresy 這邊也用現在 64 位元的 Visual Studio 2022 和 Ubuntu 22 的 g++ 12.1 測試的一下,狀況如下:

Type
C++ Standard
Visual C++ 2022
g++ 12.1
char
8 bit
8 bit
8 bit
short
16 bit
16 bit
16 bit
int
16 bit
32 bit
32 bit
long
32 bit
32 bit
64 bit
long long
64 bit
64 bit
64 bit

恩,滿訝異的是,和 Heresy 過去認知的不太一樣了,原來 int 不見得會比 short 大?!

而這邊也可以看到,兩個不同的平台上,對於 long 的實作是不同的;而實際上,比較早期的 Win16 API 似乎就真的會變成 shortint 同樣是 16 bit。

實際上,C++ 標準是要求這幾種型別的大小要符合下面的狀況:

1 == sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)

通常這邊的差異不會有太大的問題,但是如果是要以 binary 的形式來做資料的儲存、傳遞,或是跨系統、或是其他需要嚴格資料大小的情境,這邊的不同可能就會造成嚴重的問題了!

實際上,在 C99 的時候,C 語言就透過 <stdint.h> 定義了固定大小的整數型別(Fixed width integer type、參考);而在 C++11 的時候,也正式加入了對應的 <cstdint>,針對這部分做出支援(參考)。

這邊主要是定義了:int8_tint16_tint32_tint64_t 這種明確標示出用了多少記憶體空間的型別。

同時,對於無號整數的部分,也有 uint8_tuint16_tuint32_tuint64_t

透過這種型別,基本上就可以更明確地宣告特定記憶體量的整數型別變數了。

而如果只是想要用系統中可以使用的最大整數型別的話,則也可以使用 intmax_t / uintmax_t;一般來說應該都會是 int64_t  就是了。

另外,這邊個人覺得比較有趣的,是在有號整數的部分,在 C++ Reference 上都是標記成「optional」的?


除了上面這些比較直覺的型別定義之外,這邊其實也還有一些有趣的型別。

像是 int_fastN_t / uint_fastN_t 這類的型別,則是要使用至少有 N bits、處理速度最快的型別;如果很在意速度的話,或許可以透過使用這種型別,讓編譯器來決定要用多大的記憶體。
int_fast16_t 來說,在 Visual Studio 裡面測試是 32 bit、在 Ubuntu 的 g++ 則直接跳到 64 bit 了。

int_leastN_t / uint_leastN_t 則是代表至少要有 N bits、使用記憶體最小的型別。
不過這個個人就比較不知道該怎麼用了?


而如果要取得特定型別的數值範圍的話,除了可以用 <limits>std::numeric_limits<TYPE> 這提供的各種函式(參考)來確認之外,在 <cstdint> 中也根據不同的型別提供了巨集形式的最大值和最小值。

像是 int8_t 的值的範圍就是 INT16_MIN ~ INT16_MAX;而 uint_fast32_t 的範圍則是 0 ~ UINT_FAST32_MAX


此外,在字元的部分,除了本來的 charwchar_t 之外,現在也多出了 char8_tchar16_tchar32_t 這種對應 UTF-8、UTF-16、UTF-32 的字元型別(參考);不過在規範上,他們似乎不保證是 8 / 16 / 32 bit,而是類似 int_leastN_t 這樣,是要求可以處理對應的資料而已。

而對應的字串也多了對應的 std::u8stringstd::u16stringstd::u32string參考);但是以 C++20 的標準來說,這些新的字串型別算是相容性極差、相當難以使用的。

而在 C++23 的標準,也針對了浮點數的部分,增加了 <stdfloat>、提供了類似的型別定義(參考參考),這邊包括了:float16_tfloat32_tfloat64_tfloat128_tbfloat16_t 這些型別。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *