在使用C語言過程中可能需要接觸長整數類型,其中包括固定長度數據類型的聲明、輸入輸出函數的標志符等細節,在此記錄。
int64_t 與 uint64_t
C的標准只規定特定數據類型需要實現的最小長度,特定類型的具體長度取決於編譯器實現。為了增強程序的可移植性,C99標准增加了對固定長度的整數類型的支持。
對固定長度類型的定義位於頭文件 stdint.h 中。其中包括固定長度有符號整數類型 intN_t 和固定長度無符號整數類型 uintN_t,分別表示固定占用 N bits長度的整數類型( N = 8、16、32、64)。
圖示為CodeBlock13.12中頭文件 stdint.h 對 int64_t 和 uint64_t 的定義,可以看到它們是通過對 long long 和 unsigned long long 的 typedef 聲明實現的。
相應格式字符串
對於定義在頭文件 stdint.h 中的類型 ,其printf和scanf的格式字符串在頭文件 inttypes.h 中實現。
printf輸出
對於printf使用的格式化標識符,一般格式為 PRI + format + type 。其中 format規定輸出的格式,可以為 d( decimal ,十進制) 、h( hexadecimal ,十六進制) 、o( octal , 八進制)、u( unsigned ,無符號)等,type 為對應的數據類型,可以為 N 。( 實際type還可以為FASTN、LEASTN、PTR 和 MAX等,具體可見 C data types - Wikipedia )
如對於int64_t數據類型的輸出,可以使用格式標志符 PRId64。
實際上,各個格式化標志符的定義在頭文件inttypes.h中。可以看到,實際可直接使用格式化標志符%I64d來輸出 uint64_t類型。
這也從解釋了為什么需要將 PRIu64 獨立書寫,這是由於使用格式化字符串" %PRIu64 "時,編譯器會將 " " 間的所有字符均視為字符串的一部分,這樣在預處理階段便無法對 PRIu64 的宏定義進行替換。將PRIu64獨立出來后,其會在預編譯階段被替換為" I64u " (注意這里替換的結果包含引號),即格式化字符串變為 " % " " I64u " "\n",在C語言中被當作“ %I64u\n”處理,從而保證結果正確輸出。
scanf輸入
對應的scanf使用的格式化標識符,一般格式為 SCN + format + type。其中 format規定輸出的格式,可以為 d( decimal ,十進制) 、h( hexadecimal ,十六進制) 、o( octal , 八進制)、u( unsigned ,無符號)等,type 為對應的數據類型,可以為 N 。
scanf的格式化標志符與printf中的定義方法大致相同,在頭文件 inttypes.h 中存在相應的宏定義,如對無符號類型的輸入的標識符如下圖所示。
unsigned long long 與 long long 類型的輸入與輸出
在CodeBlocks的頭文件 stdint.h 中存在如下表述:
一般而言C語言標准給出的 unsgned long long 與 long long 的格式化標識符分別為 llu 與 lli,但實在Windows環境下編譯時,可能尚未提供對 " ll " 格式化標志符的支持,使得使用了以上兩種格式化標識符的類型無法被正確識別。一種可行的解決方法是使用上述 int64_t 與 uint64_t 的格式化標識符,因為從頭文件 stdint.h 的定義中我們可以發現,int64_t 與 uint64_t 分別就是 long long 與 unsigned long long 的 typedef 定義,故而可以使用 PRId64 和 PRIu64 來對 long long 類型與 unsigned long long 類型進行輸出。
需要注意的是,不同的機器和編譯器對 int64_t 和 uint64_t 的實現可能並不相同,故而最好先在頭文件 stdint.h 中確認具體的定義后再根據具體的定義使用對應的格式化標識符。
其他
在程序設計時需要注意常數的類型問題,筆者在書寫簡單的測試程序時,使用如下方式,編譯器報錯"warning: left shift count >= width of type",即左移的長度大於了類型長度。
這是由於C對常數的類型確認機制決定的。整數類型常量由其值和符號共同決定。其中十進制常量的類型是 int 、 long 和 long long 中能夠容納該常量的最小長度類型。故而上例中 1 被確認為 int 類型,長度在本機器上為 32bits,故而在進行編譯時會出現錯誤。相應的,八進制和十六進制常量的類型是能容納其值的 int 、unsigned int 、long 、unsigned long 、long long 和 unsigned long long 中長度最小的類型。這里可以看到,十進制常量均為有符號類型,而八進制和十進制常量的類型有可能為無符號類型。