"int" 和 "int_fast16_t" 有什么区别?
What's the difference between "int" and "int_fast16_t"?
据我了解,C 规范说类型 int
应该是目标平台上最有效的类型,它至少包含 16 位。
这不正是 int_fast16_t
的 C99 定义吗?
也许他们把它放在那里只是为了保持一致性,因为还需要其他 int_fastXX_t
?
更新
总结以下讨论:
- 我的问题在很多方面都是错误的。 C 标准没有指定 int 的位数。它给出了它必须包含的范围 [-32767,32767]。
- 我意识到起初大多数人会说,“但这个范围意味着至少 16 位!”但是 C 不需要补码存储整数。如果他们说“16 位”,可能有一些平台具有 1 位奇偶校验、1 位符号和 14 位幅度,它们仍然“符合标准”,但不满足该范围。
- 标准没有说明 int 是最有效的类型。除了上面的大小要求之外,int 可以由编译器开发人员根据他们认为最重要的任何标准来决定。 (速度、大小、向后兼容性等)
- 另一方面,int_fast16_t 就像是向编译器提供一个提示,它应该使用性能最佳的类型,可能会以牺牲任何其他权衡。
- 同样,int_least16_t 会告诉编译器使用 >= 16 位的最小类型,即使它会更慢。适合在大型数组和内容中保存 space。
示例: 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.
另一个区别是 fast 和 least 类型是必需类型,而其他精确宽度类型是 可选:
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_MIN
和 INT_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.
int
和 int_fast16_t
的要求相似但不完全相同 -- 而且它们同样含糊不清。
在实践中,int
的大小通常是根据 "the natural size" 以外的标准来选择的——或者为了方便而解释该短语。通常选择新架构的 int
大小来匹配现有架构的大小,以最大限度地降低移植代码的难度。并且有相当强烈的动机让 int
不超过 32 位,因此类型 char
、short
和 int
可以覆盖 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.
int
和 int_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.
据我了解,C 规范说类型 int
应该是目标平台上最有效的类型,它至少包含 16 位。
这不正是 int_fast16_t
的 C99 定义吗?
也许他们把它放在那里只是为了保持一致性,因为还需要其他 int_fastXX_t
?
更新
总结以下讨论:
- 我的问题在很多方面都是错误的。 C 标准没有指定 int 的位数。它给出了它必须包含的范围 [-32767,32767]。
- 我意识到起初大多数人会说,“但这个范围意味着至少 16 位!”但是 C 不需要补码存储整数。如果他们说“16 位”,可能有一些平台具有 1 位奇偶校验、1 位符号和 14 位幅度,它们仍然“符合标准”,但不满足该范围。
- 标准没有说明 int 是最有效的类型。除了上面的大小要求之外,int 可以由编译器开发人员根据他们认为最重要的任何标准来决定。 (速度、大小、向后兼容性等)
- 另一方面,int_fast16_t 就像是向编译器提供一个提示,它应该使用性能最佳的类型,可能会以牺牲任何其他权衡。
- 同样,int_least16_t 会告诉编译器使用 >= 16 位的最小类型,即使它会更慢。适合在大型数组和内容中保存 space。
示例: 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 nameuint_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.
另一个区别是 fast 和 least 类型是必需类型,而其他精确宽度类型是 可选:
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 rangeINT_MIN
toINT_MAX
as defined in the header<limits.h>
).
对 INT_MIN
和 INT_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.
int
和 int_fast16_t
的要求相似但不完全相同 -- 而且它们同样含糊不清。
在实践中,int
的大小通常是根据 "the natural size" 以外的标准来选择的——或者为了方便而解释该短语。通常选择新架构的 int
大小来匹配现有架构的大小,以最大限度地降低移植代码的难度。并且有相当强烈的动机让 int
不超过 32 位,因此类型 char
、short
和 int
可以覆盖 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
andlong
, but places very little requirement on their size other than thatint
andshort
be at least 16 bits andlong
be at least as long asint
and not smaller than 32 bits. For 16-bit systems, most implementations assign 8, 16, 16 and 32 bits tochar
,short
,int
, andlong
, respectively. For 32-bit systems, the common practice is to assign 8, 16, 32 and 32 bits to these types. This difference inint
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, viatypedef
, integer types of various sizes. Implementations are free totypedef
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.
int
和 int_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.