64位上C的整数类型

前几天跟同事闲聊 64 位操作系统时,有人问起 64 位平台上,C 语言的数据类型如何确定的问题。以及跨平台(跨 16 位、32 位和 64 位平台)程序如何选用合适的数据类型。

我查了一下资料,记录如下:

  • char 通常被定义成 8 位宽。
  • int 通常被定义成 16 位或 32 位宽(或更高),它取决于平台。编译器将在这两者间选择最合适的字宽。
  • short 通常被定义成 16 位宽。
  • long 通常被定义成 32 位宽。 C99 为 C 语言扩展了新的整数类型 long long ,通常被定义成 64 位宽。(GNU C 亦支持)

但是 C 标准并没有定义具体的整数类型的宽度,只定义了 long long 的级别高于 long ,long 的级别高于 int ,int 的级别高于 short ,short 的级别高于 char 。(另外有 _Bool 永远是最低级别)。级别高的整数类型的宽度大于等于级别较低的整数类型。

char 的宽度用宏 CHAR_BIT 定义出来,通常为 8 ,而除了位域类型外,其它所有类型的位宽都必须是它的整数倍。

如果需要精确确定整数类型的宽度,在 C99 以及 GNU C 中,需要包含 stdint.h ,使用其中几种扩展的整数类型。

int16_t 可以保证整数长度为精确的 16 位。同样,int8_t 可以保证整数长度为精确的 8 位。类似的还有 int32_t int64_t 以及无符号类型 uint8_t 等等。

int_least16_t 可以得到一个当前平台所支持的至少有 16 位宽的最短整数类型。(其它同类型的可以类推)

int_fast32_t 可以得到当前平台下得到处理速度最快的至少为 32 位的整数类型。
intmax_t 可以获得当前平台所支持的最大宽度的整数类型。

在书写整数常数时,在数字后加上 L 表示是一个 long 类型的整数,加上 U 表示是一个 unsigned 整数,加上 LL 表示是一个 long long 类型整数。但是由于 long long 这些并不能确定准确字宽,有此需求时,可以借助宏 INTn_C(value) 来转换。例如,想指定一个 64 位整数常数 0x1234 ,可以写成 INT64_C(0x1234) 。若在当前平台上 int_least64_t 就是 long long int 的话,这个宏会被展开成 0x1234LL 。

最后再提一个很重要的扩展类型:intptr_t (无符号版本写成 uintptr_t)这个类型可以被安全的在 void * 和 整数间转换,对于写跨 64 位平台的程序非常重要。也就是说,当你需要把指针作为一个整数来运算时,转换成 intptr_t 才是安全的,可以在运算完毕安全的转回指针类型。
C 语言中,指针和整数之间的转换经常用到(多用于需要精确控制数据在内存中的精确布局时),在 32 位平台上,由于指针类型的字宽和 int 相同,所以我们不太在意这个问题。但是到了 64 位平台上,由于目前几乎所有 64 位系统都采用 LP64 模型,既整数依旧是 32 位,而指针是 64 位的。intptr_t 这个数据类型就成了安全跨平台编程的保证。

最后,附上 C99 标准文档技术修正第三版 ISO/IEC 9899:TC3

http://blog.codingnow.com/2008/01/c_int_type.html