"int" 和 "int_fast16_t" 有什么区别?

What's the difference between "int" and "int_fast16_t"?

据我了解,C 规范说类型 int 应该是目标平台上最有效的类型,它至少包含 16 位。

这不正是 int_fast16_t 的 C99 定义吗?

也许他们把它放在那里只是为了保持一致性,因为还需要其他 int_fastXX_t

更新

总结以下讨论:

示例: x86-64 上的 MSVC 具有 32 位 int,即使在 64 位系统上也是如此。 MS 选择这样做是因为太多人认为 int 总是精确的 32 位,所以很多 ABI 会崩溃。但是,如果 64 位值在 x86-64 上更快,则 int_fast32_t 可能是 64 位数字。 (我认为实际情况并非如此,但它只是说明了这一点)

int_fast16_t 保证是最快的 int,大小至少为 16 位。 int 无法保证其大小,除了:

 sizeof(char) = 1 and sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long).

并且它可以容纳 -32767 到 +32767 的范围。

(7.20.1.3p2) "The typedef name int_fastN_t designates the fastest signed integer type with a width of at least N. The typedef name uint_fastN_t designates the fastest unsigned integer type with a width of at least N."

int 是 speed/size 中的 "most efficient type" - 但 C 规范并未指定。必须是16位以上。

int_fast16_t 是速度最快的类型,至少 16 位整数的范围。

示例:出于多种原因,给定平台可能已决定 int 应该是 32 位,而不仅仅是速度。对于 16 位整数,同一系统可能会发现不同的类型是最快的。

示例:在 64 位机器中,人们希望将 int 作为 64 位,编译器可能会使用具有 32 位 int 编译的模式以实现兼容性。在这种模式下,int_fast16_t 可以是 64 位,因为它本身是最快的宽度,因为它避免了对齐问题等。

不同之处在于 fast 类型允许比它们的对应类型 更宽(没有 fast) 用于 efficiency/optimization 目的。但是 C 标准决不能保证它们实际上 更快。

C11, 7.20.1.3 最快的最小宽度整数类型

1 Each of the following types designates an integer type that is usually fastest 262) to operate with among all integer types that have at least the specified width.

2 The typedef name int_fastN_t designates the fastest signed integer type with a width of at least N. The typedef name uint_fastN_t designates the fastest unsigned integer type with a width of at least N.

262) The designated type is not guaranteed to be fastest for all purposes; if the implementation has no clear grounds for choosing one type over another, it will simply pick some integer type satisfying the signedness and width requirements.

另一个区别是 fastleast 类型是必需类型,而其他精确宽度类型是 可选:

3 The following types are required: int_fast8_t int_fast16_t int_fast32_t int_fast64_t uint_fast8_t uint_fast16_t uint_fast32_t uint_fast64_t All other types of this form are optional.

As I understand it, the C specification says that type int is supposed to be the most efficient type on target platform that contains at least 16 bits.

以下是标准关于 int 的实际说法:(N1570 draft,第 6.2.5 节,第 5 段):

A "plain" int object has the natural size suggested by the architecture of the execution environment (large enough to contain any value in the range INT_MIN to INT_MAX as defined in the header <limits.h>).

INT_MININT_MAX 的引用可能有点误导;这些值是根据类型 int 的特征选择的,而不是相反。

而短语“ 自然大小”也有点误导。根据目标体系结构,整数类型可能不会只有一个 "natural" 大小。

在其他地方,标准说 INT_MIN 必须最多 -32767,并且 INT_MAX 必须至少 +32767,这意味着 int至少是 16 位。

以下是标准对 int_fast16_t (7.20.1.3) 的描述:

Each of the following types designates an integer type that is usually fastest to operate with among all integer types that have at least the specified width.

带脚注:

The designated type is not guaranteed to be fastest for all purposes; if the implementation has no clear grounds for choosing one type over another, it will simply pick some integer type satisfying the signedness and width requirements.

intint_fast16_t 的要求相似但不完全相同 -- 而且它们同样含糊不清。

在实践中,int 的大小通常是根据 "the natural size" 以外的标准来选择的——或者为了方便而解释该短语。通常选择新架构的 int 大小来匹配现有架构的大小,以最大限度地降低移植代码的难度。并且有相当强烈的动机让 int 不超过 32 位,因此类型 charshortint 可以覆盖 8、16 和32 位。在 64 位系统上,特别是 x86-64,"natural" 大小可能是 64 位,但大多数 C 编译器使 int 成为 32 位而不是 64 位(有些编译器甚至使 long 只是32 位)。

我怀疑 int_fast16_t 的基础类型的选择不太依赖于这些考虑,因为使用它的任何代码都明确要求快速的 16 位有符号整数类型。许多现有代码对 int 的特性做出了超出标准保证范围的假设,如果编译器开发人员希望使用他们的编译器,则必须迎合此类代码。

在某些平台上,使用 16 位值可能比使用 32 位值很多[例如8 位或 16 位存储需要执行 32 位加载、修改加载值并写回结果]。即使在高速缓存中可以容纳两倍于 32 位值的 16 位值(在 32 位系统上 16 位值比 32 位值快的正常情况),每次写入都需要在读取之前会抵消任何可能产生的速度优势,除非数据结构的读取频率远高于写入频率。在这样的平台上,像 int_fast16_t 这样的类型可能是 32 位。

话虽如此,不幸的是,标准不允许对编译器最有用的语义,即允许地址未被采用的 int_fast16_t 类型的变量任意表现为 16 -bit 类型或更大的类型,具体取决于什么方便。例如,考虑方法:

int32_t blah(int32_t x)
{
  int_fast16_t y = x;
  return y;
}

在许多平台上,存储在内存中的16位整数通常可以像存储在寄存器中的那样进行操作,但是没有对寄存器执行16位操作的指令。如果存储在内存中的 int_fast16_t 变量只能保存 -32768 到 +32767,则同样的限制将适用于存储在寄存器中的 int_fast16_t 变量。由于将过大的值强制转换为太小而无法容纳它们的有符号整数类型是实现定义的行为,这将迫使上述代码添加指令以在返回之前对 x 的低 16 位进行符号扩展;如果标准允许这种类型,灵活的 "at least 16 bits, but more if convenient" 类型可以消除对此类指令的需要。

来自 C99 基本原理 7.8 整数类型的格式转换 <inttypes.h>(标准附带的文档),强调我的:

C89 specifies that the language should support four signed and unsigned integer data types, char, short, int and long, but places very little requirement on their size other than that int and short be at least 16 bits and long be at least as long as int and not smaller than 32 bits. For 16-bit systems, most implementations assign 8, 16, 16 and 32 bits to char, short, int, and long, respectively. For 32-bit systems, the common practice is to assign 8, 16, 32 and 32 bits to these types. This difference in int size can create some problems for users who migrate from one system to another which assigns different sizes to integer types, because Standard C’s integer promotion rule can produce silent changes unexpectedly. The need for defining an extended integer type increased with the introduction of 64-bit systems.

The purpose of <inttypes.h> is to provide a set of integer types whose definitions are consistent across machines and independent of operating systems and other implementation idiosyncrasies. It defines, via typedef, integer types of various sizes. Implementations are free to typedef them as Standard C integer types or extensions that they support. Consistent use of this header will greatly increase the portability of a user’s program across platforms.

intint_fast16_t 之间的主要区别是后者很可能没有这些 "implementation idiosyncrasies"。你可能会认为它是这样的:

我不关心当前 OS/implementation "politics" int 大小。只要告诉我最快的至少 16 位的有符号整数类型是什么。

这两种类型可能有何不同的示例:假设有一个架构,其中 8 位、16 位、32 位和 64 位算法的速度同样快。 (i386 接近。)然后,实施者可能会使用 LLP64 模型,或者更好的是允许程序员在 ILP64、LP64 和 LLP64 之间进行选择,因为那里有很多代码假设 long 正好是 32 位,并且sizeof(int) <= sizeof(void*) <= sizeof(long)。任何 64 位实现都必须至少违反这些假设之一。

在那种情况下,int 可能是 32 位宽,因为这将破坏来自其他系统的代码最少,但 uint_fast16_t 仍然可以是 16 位宽,节省 space.