【问题标题】:In new code, why would you use `int` instead of `int_fast16_t` or `int_fast32_t` for a counting variable?在新代码中,为什么要使用 `int` 而不是 `int_fast16_t` 或 `int_fast32_t` 作为计数变量?
【发布时间】:2017-09-12 11:41:01
【问题描述】:

如果您需要一个计数变量,那么您的整数肯定必须支持上限和下限。那么为什么不通过选择适当的 (u)int_fastxx_t 数据类型来指定这些限制呢?

【问题讨论】:

  • int is short to type”可能是最好的理由。 int 在语义上实际上是 int_fast16_t(即,保证至少为 16 位的快速类型),但实际上,在 x86_64 Linux 上,int 是 32 位,所有快速类型除了 (u)int_fast8_t 是64。无论您使用什么,编译器都可能会将常用的​​计数器放入寄存器中,因此 AFAIK,您最好使用具有寄存器宽度的东西,因为无论如何都会使用它。
  • 因为您在编写 C++ 代码时大多不需要关心这些低级细节。 int 是对“具有合理性能的通用整数” 的完美抽象。只有在必要时才放弃抽象,而不是相反。
  • @ChristianHackl 但是知道什么时候放弃抽象需要你知道int在你的代码将运行的每个平台上的大小。
  • @traal - 买你也不知道int_fast16_t的大小...

标签: c++ c++11 int


【解决方案1】:

最简单的原因是人们更习惯于int,而不是 C++11 中引入的其他类型,而且它是语言的“默认”整数类型(C++ 也有);该标准在[basic.fundamental/2] 中指定:

普通整数具有执行环境架构所建议的自然大小46;提供其他有符号整数类型以满足特殊需要。

46) 即大到足以包含INT_MININT_MAX 范围内的任何值,如标头<climits> 中所定义。

因此,当需要一个通用整数时,不需要有特定的范围或大小,程序员倾向于只使用int。虽然使用其他类型可以更清楚地传达意图(例如,使用int8_t 表示该值不应超过127),但使用int 也可以传达这些细节对于手头的任务并不重要,同时提供一点余地来捕获超出所需范围的值(例如,如果系统使用模运算处理有符号溢出,int8_t 会将313 视为57,从而使无效值更难排除故障);通常,在现代编程中,它要么表示该值可以在系统的字长(int 应该表示)内表示,要么表示该值可以在 32 位内表示(几乎总是 @ 987654335@ 在 x86 和 x64 平台上)。

Sized 类型还存在一个问题,即(理论上)最知名的 intX_t 行仅在支持 完全 X 位大小的平台上定义。虽然int_leastX_t 类型保证在所有平台上都被定义,并且保证至少是 X 位,但很多人不想在不需要时输入那么多,因为当你需要经常指定类型。 [你不能使用auto,因为它将整数文字检测为ints。这可以通过使用用户定义的文字运算符来缓解,但这仍然需要更多的时间来输入。]因此,如果这样做是安全的,他们通常会使用int

或者简而言之,int 旨在成为正常操作的首选类型,而其他类型旨在用于异常情况。许多程序员出于习惯而坚持这种心态,并且仅在明确需要特定范围和/或大小时才使用大小类型。这也相对较好地传达了意图; int 表示“数字”,intX_t 表示“总是适合 X 位的数字”。

int 已演变为非正式的“32 位整数”的意思并没有帮助,因为 32 位和 64 位平台通常使用 32 位 ints。很可能许多程序员希望int 在现代总是至少为 32 位,以至于如果他们必须为 不 支持 32 位 ints.


相反,大小类型通常在明确需要特定范围或大小时使用,例如在定义需要在具有不同数据模型的系统上具有相同布局的struct 时。当使用有限的内存时,它们也可以证明是有用的,使用可以完全包含所需范围的最小类型。

例如,打算在 16 位和 32 位系统上具有相同布局的 struct 将使用 int16_tint32_t 而不是 int,因为 int 在大多数情况下是 16 位16 位数据模型和 LP32 32 位数据模型(由 Win16 API 和 Apple Macintoshes 使用),但 ILP32 32 位数据模型中的 32 位(由 Win32 API 和 *nix 系统使用,有效地使其成为事实上的“标准”32 位模型)。

同样,在 32 位和 64 位系统上具有相同布局的 struct 将使用 int/int32_tlong long/int64_t 而不是 long,这是由于 long在不同的模型中具有不同的大小(LP64 中的 64 位(由 64 位 *nix 使用)、LLP64 中的 32 位(由 Win64 API 使用)和 32 位模型)。

注意还有第三种64位模型,ILP64,其中int是64位;此模型很少使用(据我所知,它仅用于早期的 64 位 Unix 系统),但如果需要与 ILP64 平台的布局兼容,则要求使用大小超过 int 的类型。

【讨论】:

  • 您能否提供一个示例,说明“需要一个通用整数,它不需要具有特定范围或大小”?例如,如果我遍历一周中的几天,我必须选择一个可以容纳多达 7 个唯一值的数据类型,因此它的大小至少需要为 3 位。但是,使用具有 no 大小要求的整数的示例是什么?
  • @traal - 我认为您忘记了系统除了整数大小之外还有其他限制。在具有 16 位整数的计算机上,您要循环什么?当然,你不会有一个包含一百万个对象的数组,而不会在 int 中的位之前很久就耗尽内存。
  • @traal 我能想到的最常见的是循环条件和计算过程中使用的中间值。当然,这些可以有特定的范围(并且通过扩展,特定的大小要求),但它们通常是模糊的,因此如有必要有增长空间(如果程序已经使用更大的类型,则更容易更新程序以适应更大的值必要)。
  • 问题基本上是很多人的做法和你的相反;在你喜欢施加严格限制并且只在必要时放松它们的地方,许多程序员更喜欢使用宽松限制,并且只在必要时收紧它们。你会在哪里使用int16_t,因为一个值总是在-10'000..10'000的范围内,例如,许多程序员会使用int,并且只有在他们需要节省内存并且不需要时才将其更改为int16_t预计需求会变得比int16_t 可以存储的更大。 (这在更有限系统的程序员中不太普遍。)
  • @JustinTime 所以你是说int 避免了为你的int8_t 使用typedef 的需要(或者当你需要更大的东西时花时间重构)并记录你选择的原因int8_t 而不是 int16_t 首先。这对我来说似乎很笨拙,所以我想我们必须同意不同意。
【解决方案2】:

有几个原因。一,这些长名称使代码的可读性降低。二,你可能会引入很难找到的错误。假设您使用了 int_fast16_t,但您确实需要数到 40,000。该实现可能使用 32 位并且代码工作得很好。然后,您尝试在使用 16 位的实现上运行代码,您会遇到难以发现的错误。

注意:在 C/C++ 中,您有 char、short、int、long 和 long long 类型,它们必须涵盖 8 到 64 位,因此 int 不能是 64 位(因为 char 和 short 不能涵盖 8、16 和 32 位),即使 64 位是自然字长。例如,在 Swift 中,Int 是自然整数大小,可以是 32 位和 64 位,而您有 Int8、Int16、Int32 和 Int64 来表示显式大小。 Int 是最好的类型,除非您绝对需要 64 位,在这种情况下您使用 Int64,或者如果您需要节省空间。

【讨论】:

  • "int 不能是 64 位" - 我认为这不是真的。没有什么说必须存在 8、16 和 32 位的类型。
  • 从标题stdint.h你可以声明整数,它是64位-int64_t
  • 实现者倾向于更喜欢提供涵盖 8、16、32 和 64 位大小的预定义类型,但标准并不要求它。我使用 64 位 int 的 C 实现。两者都有 8 位 char;一个有 32 位 short,另一个有 64 位 short。两者都没有 16 位整数类型,后者没有 32 位整数类型。
  • int 同样可能会引入难以发现的错误。如果您计算超出预期最大值的大小,您应该编写一个断言。没有固定尺寸的类型会给您带来任何优势。
  • 没有 8 位最小值。您可以有一个 16 位字符,这意味着该系统上的最小类型至少为 16 位。
猜你喜欢
  • 2016-07-09
  • 2019-02-28
  • 2015-05-30
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 2019-12-18
相关资源
最近更新 更多