“int”和“int_fast16_t”有什么区别?

时间:2015-06-19 15:38:14

标签: c int c99 portability c89

据我了解,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位的最小类型,即使它会更慢。适用于保留大型阵列和空间中的空间。

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

7 个答案:

答案 0 :(得分:31)

int在速度/大小方面是“最有效的类型” - 但不是根据C规范指定的。它必须是16位或更多位。

int_fast16_t是速度最有效的类型,至少 16位int的范围。

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

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

答案 1 :(得分:24)

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

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

它可以保持-32767到+32767的范围。

  

(7.20.1.3p2)“typedef名称int_fastN_t指定宽度至少为 N 的最快签名整数类型.typedef名称uint_fastN_t指定最快无符号整数类型,宽度至少为 N 。“

答案 2 :(得分:7)

  

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

以下是int标准实际所说的内容:(N1570 draft,第6.2.5节,第5段):

  

A&#34; plain&#34; int 对象具有自然大小   执行环境的体系结构(足够大以包含任何    INT_MIN INT_MAX 范围内的值,如   标题 <limits.h> )。

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

短语&#34; 自然尺寸&#34;也有点误导。根据目标架构,可能不会只有一个&#34;自然&#34;整数类型的大小。

在其他地方,标准规定INT_MIN最多必须为-32767,而INT_MAX必须至少为+32767,这意味着int位于至少16位。

以下是关于int_fast16_t(7.20.1.3)的标准:

  

以下每种类型都指定一个通常的整数类型   在所有至少具有的整数类型中运行最快   指定的宽度。

脚注:

  

不保证指定类型对所有目的都是最快的;   如果实施没有明确的理由选择一种类型   另外,它会简单地选择一些满足的整数类型   签名和宽度要求。

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

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

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

答案 3 :(得分:2)

不同之处在于,为了效率/优化目的, fast 类型允许更宽比其对应物(没有 fast 更宽。但是C标准并不能保证它们实际上更快。

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

  

1以下每种类型都指定一个整数类型   通常最快262)在所有具有的整数类型中操作   至少是指定的宽度。

     

2 typedef名称int_fastN_t指定最快的有符号整数   宽度至少为N的类型.typedef名称为uint_fastN_t   指定宽度至少为最快的无符号整数类型   Ñ

     

262)不保证指定类型对所有人来说都是最快的   目的;如果实施没有明确的选择依据   一种类型而不是另一种类型,它只会选择一些整数类型   满足签名和宽度要求。

另一个区别是 fast less 类型是必需类型,而其他确切的宽度类型是可选

  

3需要以下类型:int_fast8_t int_fast16_t   int_fast32_t int_fast64_t uint_fast8_t uint_fast16_t uint_fast32_t   uint_fast64_t此表单的所有其他类型都是可选的。

答案 4 :(得分:2)

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

  

C89指定该语言应支持四个签名和   无符号整数数据类型,charshortintlong,但地点   除了intshort之外,对其大小的要求非常低   至少16位且long至少与int一样长且不小   超过32位。对于16位系统,大多数实现分配8,16,   分别为charshortintlong的16位和32位。对于32位   系统,通常的做法是分配8,16,32和32位   这些类型。 int大小的这种差异可能会产生一些问题   从一个系统迁移到另一个系统的用户分配不同的用户   size到整数类型,因为标准C的整数提升规则   可以意外地产生无声的变化。需要定义一个   随着64位的引入,扩展整数类型增加   系统

     

<inttypes.h>的目的是提供一组整数类型   定义在整个机器上是一致的,并且独立于   操作系统和其他实现特性。它定义,   通过typedef,各种大小的整数类型。实施是免费的   将它们作为标准C整数类型或扩展名typedef   支持。一致使用此标头将大大增加   跨平台的用户程序的可移植性。

intint_fast16_t之间的主要区别在于后者很可能没有这些“实现特性”。您可能会将其视为:

我不关心int大小的当前操作系统/实施“政治”。只要给我一个最快签名的整数类型,至少16位是。

答案 5 :(得分:1)

在某些平台上,使用16位值可能比使用32位值 更慢[例如]一个8位或16位存储器需要执行32位加载,修改加载的值,并写回结果]。即使一个高速缓存中的16位值与32位值一样多(正常情况下16位值比32位系统上的32位值快),也需要每次写入在读取之前会否定可能产生的任何速度优势,除非数据结构的读取频率远远高于写入数据结构。在这样的平台上,类似int_fast16_t的类型可能是32位。

话虽如此,标准不会遗憾地允许编译器最有用的语义,这将允许类型为int_fast16_t的变量,其地址不会被任意地表现为16位类型或更大的类型,取决于方便的。例如,考虑一下方法:

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位进行符号扩展;如果标准允许这种类型,灵活的“至少16位,但更方便”类型可以消除对此类指令的需要。

答案 6 :(得分:1)

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

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