跳转到内容

C 编程/stdint.h

来自维基教科书,开放的书籍,开放的世界
(从 C 编程/C 参考/stdint.h 重定向)

stdint.h头文件,它包含在 C 标准库 中,并于 C99 标准库 的 7.18 节中引入,允许程序员通过提供一组类型定义来编写更可移植的代码,这些类型定义指定了精确宽度整数类型,以及使用宏[1] 定义的每个类型的允许最小值和最大值。此头文件对于嵌入式编程尤其有用,嵌入式编程通常涉及对特定硬件 I/O 寄存器的相当多的操作,这些寄存器需要具有固定宽度、特定位置和精确对齐的整数数据。stdint.h(对于 C 或 C++)cstdint(对于 C++) 可以下载或快速创建,如果它们没有提供的话。

精确宽度整数类型的命名约定为 intN_t 用于 带符号 intuintN_t 用于 无符号 int [1] 。例如,int8_tuint64_t 可以与定义它们各自范围的 INT8_MININT8_MAX0(零)到 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>_tu<something>_t 必须是对应的有符号和无符号整数类型。对于标记为可选的类型,实现必须同时定义 <something>_tu<something>_t,或者两者都不定义。这些类型的限制应使用类似于下面描述的格式使用宏定义。

如果一个类型是 [u]<something>N_t 的形式(或类似地用于预处理器定义),N 必须是一个正十进制整数,没有前导 0。

精确宽度整数类型

[编辑 | 编辑源代码]

这些是 intN_tuintN_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_tuint_leastN_tint_leastN_t 是一个有符号整数,uint_leastN_t 是一个无符号整数[1]

标准要求这些类型至少包含 N 个位,并且没有比它们更小的具有相同符号的类型包含 N 个或更多位。例如,如果一个系统只提供 uint32_tuint64_t,那么 uint_least16_t 必须等同于 uint32_t

实现必须为以下 N 定义这些类型:8、16、32、64。其他任何 N 都是可选的。

这些类型的限制使用以下格式的宏定义

  • INT_LEASTN_MAXint_leastN_t 有符号版本的最大值(2N−1 − 1 或更大)。
  • INT_LEASTN_MINint_leastN_t 有符号版本的最小值(−2N−1 + 1 或更小)。
  • UINT_LEASTN_MAXuint_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_tuint_fastN_t

标准没有对这些类型进行任何强制要求,除了它们的宽度必须大于或等于 N 之外。它还将如何定义 "快速" 整数类型留给实现者决定。

实现必须为以下 N 定义这些类型:8、16、32、64[2]

这些类型的限制使用以下格式的宏定义

  • INT_FASTN_MAXint_fastN_t 有符号版本的最大值(2N−1 − 1 或更大)。
  • INT_FASTN_MINint_fastN_t 有符号版本的最小值(−2N−1 + 1 或更小)。
  • UINT_FASTN_MAXuint_fastN_t 无符号版本的最大值(2N − 1 或更大)[1]

足够大的整数,可以容纳指针

[编辑 | 编辑源代码]

intptr_tuintptr_t 分别是有符号和无符号整数,保证能够容纳指针的值。这两个类型是可选的。

这些类型的限制通过以下宏定义:

  • INTPTR_MINintptr_t 的最小值(−32,767 [−215 + 1] 或更小)。
  • INTPTR_MAXintptr_t 的最大值(32,767 [215 − 1] 或更大)。
  • UINTPTR_MAXuintptr_t 的最大值(65,535 [216 − 1] 或更大)[3]

最大宽度整数类型

[编辑 | 编辑源代码]

intmax_tuintmax_t 是支持的最大宽度的有符号和无符号整数。换句话说,它们是限制最大的整数类型。

这些类型的限制使用以下格式的宏定义

  • INTMAX_MAXintmax_t 有符号版本的最大值(9,223,372,036,854,775,807 [263 − 1] 或更大)。
  • INTMAX_MINintmax_t 有符号版本的最小值(−9,223,372,036,854,775,807 [−263 + 1] 或更小)。
  • UINTMAX_MAXuintmax_t 无符号版本的最大值(18,446,744,073,709,551,615 [264 − 1] 或更大)。

还定义了用于转换常量十进制、八进制或十六进制值的宏,这些值将适合相应的类型。

  • INTMAX_C(value) 将被替换为适合 intmax_t 的值。
  • UINTMAX_C(value) 将被替换为适合 uintmax_t 的值[1]

其他整数限制

[编辑 | 编辑源代码]
  • PTRDIFF_MINptrdiff_t 的最小值。
  • PTRDIFF_MAXptrdiff_t 的最大值。
  • SIZE_MAXsize_t 的最大值(216 − 1 或更大)。
  • WCHAR_MINwchar_t 的最小值。
  • WCHAR_MAXwchar_t 的最大值。
  • WINT_MINwint_t 的最小值。
  • WINT_MAXwint_t 的最大值。
  • SIG_ATOMIC_MINsig_atomic_t 的最小值。
  • SIG_ATOMIC_MAXsig_atomic_t 的最大值。

批评和注意事项

[编辑 | 编辑源代码]
  • 一些(不符合标准的)实现将 C99 支持附加到 C89 运行时库之上。[需要引用] 这样做的结果之一是,新的 printfscanf 指定符不被识别,可能会导致一些未定义的行为。解决此问题的典型方法是
    • 最常见(也是最错误)的方法是使用 longunsigned long 类型作为中间步骤,并将这些类型传递给 printfscanf。对于小于 32 位的精确、最小和快速整数类型,这种方法可以正常工作,但在 ptrdiff_tsize_t 以及大于 32 位的类型(通常在使用 32 位 long 和 64 位指针的平台上)可能会出现问题。
    • 不直接使用 scanf,而是手动读入缓冲区,调用 strto<i|u>max,然后将其转换为所需类型。不过,这不能帮助打印整数。
    • 使用与 C99 兼容的第三方 printfscanf 库。
    • 使用 C99 标准打印格式指定符。例如 PRId64。这些指定符在 inttypes.h 中声明。
  • 整数等级和对应整数类型的规则可能会迫使实现者在不支持整数类型、做出糟糕的妥协或以不符合标准的方式支持整数类型之间做出两难选择。
    • 例如,有些机器要么对极大的有符号整数寄存器提供特殊支持,要么对极大的无符号整数寄存器提供特殊支持,而没有对其他类型提供支持。[需要引用] 实现可以选择不将此功能暴露给 C 实现,合成一个缓慢的类型作为对应的整数类型,合成一个奇怪的对应整数类型,或者将整数暴露给程序员,而不将其设置为 [u]intmax_t 类型或合成一个对应的整数类型。
  • [u]intN_t 类型是在希望拥有保证的二进制补码整数类型和希望拥有保证的没有填充位的类型之间的折衷方案(与更细粒度的方案相比,后者将定义更多类型)。由于 [u]intN_t 类型采取 "全有或全无" 的方式,因此根据它们是否关心速度、程序员的便利性或标准符合性,实现可能不得不玩上面描述的同类游戏。

另请参见

[编辑 | 编辑源代码]

注释和参考文献

[编辑 | 编辑源代码]
  1. a b c d e f g h 从技术上讲,它实际上允许 0 个或多个值位,但你构建它的唯一方法是使用一个有符号整数的单比特位域
  2. http://www.tuxgraphics.org/common/src2/article09043/avr-libc-user-manual-1.6.4/group__avr__stdint.html
  3. http://linux.die.net/man/3/intptr_t
  • stdint.h: 整数类型 – 基础定义参考,单一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.hinttypes.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库,就可以在任何平台上进行编译而无需更改。
华夏公益教科书