【问题标题】:Is there a reason to use C++11's std::int_fast32_t or std::int_fast16_t over int in cross-platform code?是否有理由在跨平台代码中使用 C++11 的 std::int_fast32_t 或 std::int_fast16_t 而不是 int ?
【发布时间】:2016-07-09 18:05:12
【问题描述】:

在 C++11 中,我们提供了固定宽度的整数类型,例如 std::int32_tstd::int64_t,它们是可选的,因此对于编写跨平台代码不是最佳选择。然而,我们也得到了这些类型的非可选变体:例如“快速”变体,例如std::int_fast32_tstd::int_fast64_t,以及“最小尺寸”变体,例如std::int_least32_t,它们的大小都至少是指定的位数。

我正在编写的代码是基于 C++11 的跨平台库的一部分,它支持在最流行的 Unix/Windows/Mac 编译器上进行编译。现在出现的一个问题是,用 C++11 固定宽度整数类型替换代码中现有的整数类型是否有优势。

使用像std::int16_tstd::int32_t 这样的变量的一个缺点是无法保证它们可用,因为只有在实现直接支持该类型时才提供它们(根据http://en.cppreference.com/w/cpp/types/integer)。

但是,由于int 至少有 16 位,而且 16 位对于代码中使用的整数来说已经足够大了,那么 std::int_fast16_t 在 int 上的用法呢?以这种方式将所有int 类型替换为std::int_fast16_t 并将所有unsigned int 替换为std::uint_fast16_t 是否有好处,或者这是否不必要?

同理,如果知道所有支持的平台和编译器都具有至少 32 位大小的 int,那么将它们分别替换为 std::int_fast32_tstd::uint_fast32_t 是否有意义?

【问题讨论】:

  • 你的“缺点”似乎是基于一个假设。谁说std::int16_tstd::int32_t 可能会消失?毕竟,它们是标准所要求的。
  • 如果您想确保您的 int 至少为 32 位宽,请执行此操作。普通int不做这样的保证。
  • @GregHewgill 它们是可选的。我的意思是,如果它们以前在操作系统和编译器的未来版本中受到支持,它们可能不受支持。我不知道任何不提供 std::int16_t 和 std::int32_t 的操作系统和编译器,但由于它们仅在本机已经存在此大小的整数时才不是可选的,因此无法保证它们的存在。另请参阅:stackoverflow.com/questions/32155759/… 如果您了解更多,您可以在这里回答:)
  • 未来很难预测。潜在地,一切都可以在新标准中“消失”。但实际上不太可能 :) 但是,fast 类型的好处是合理的 - 它们在 当前 版本中是强制性的。下一个标准可以使它们成为可选的吗?是的。但!它们不能保证有那么多位。它们可能更宽
  • @GregHewgill - 它们是“可选的”,因为如果目标平台没有该大小的合理类型,它们就不需要存在。这在当今很不寻常,但整数类型没有内在的理由是 2 的幂;过去有些处理器的倍数是 9。在这样的平台上,int16_t 可能不存在,但 int_fast16_tint_least16_t 会存在。

标签: c++ c++11 std


【解决方案1】:

int 在当前计算机和编译器上可以是 16、32 甚至 64 位。未来,它可能会更大(比如 128 位)。

如果你的代码没问题,那就去吧。

如果您的代码仅经过测试并使用 32 位整数,请考虑使用 int32_t。然后,当在没有 32 位整数的系统上运行时,代码将在编译时而不是在运行时失败(这在今天极为罕见)。

int_fast32_t 是您需要至少 32 位的时候,但您非常关心性能。在将 32 位整数加载为 64 位整数的硬件上,然后在繁琐的过程中将位移回 32 位整数,int_fast_32_t 可能是 64 位整数。这样做的代价是,在不知名的平台上,您的代码行为会大不相同。

如果您不在此类平台上进行测试,我建议您不要这样做。

在构建时中断通常比在运行时中断要好。如果并且当您的代码实际运行在需要这些功能的一些不起眼的处理器上时,然后修复它。 “你可能不需要它”的规则适用。

保守一点,在未经测试的硬件上产生早期错误,当您需要移植到所述硬件时,请执行可靠的工作和测试。

简而言之:

当且仅当您在 int 大小变化的平台上测试您的代码(并将继续测试它),并且您已经证明性能改进是值得的时才使用 int_fast##_t未来维护。

int##_t 与常见的## 大小一起使用意味着您的代码将无法在您尚未测试过的平台上编译。这很好;未经测试的代码是不可靠的,不可靠的代码通常比无用的代码更糟糕。

如果不使用int32_tint,您的代码有时会有ints 是32,有时是整数是64(理论上更多),有时是ints 是16。如果你愿意在每一个这样的int 中测试和支持每一个这样的案例,那就去吧。

请注意,int_fast##_t 的数组可能存在缓存问题:它们可能过大。例如,int_fast16_t 可以是 64 位。几千或几百万个数组可能单独使用起来很快,但是由于它们的体积导致的缓存未命中可能会使它们总体上变慢;并且将事物换成较慢存储的风险也在增加。

int_least##_t 在这些情况下会更快。

这同样适用于网络传输和文件存储的数据,而且网络/文件数据通常必须遵循在编译器/硬件更改时稳定的格式这一明显问题。然而,这是一个不同的问题。

但是,当使用固定宽度整数类型时,您必须特别注意 int、long 等仍然具有与以前相同的宽度这一事实。整数提升仍然基于 int 的大小,这取决于您使用的编译器。代码中的整数将是 int 类型,具有相关的宽度。如果您使用不同的编译器编译代码,这可能会导致不需要的行为。更多详细信息:https://stackoverflow.com/a/13424208/3144964

【讨论】:

  • 首先,感谢您的快速而有帮助的回答!不幸的是,你写的太快了,我仍然在修正我在问题中犯的一个错误(忘了提到支持的系统中的整数至少是 32 位的假设),现在问题扩大了一点。很抱歉。
  • @ident 我添加了一两段。
  • 您应该指出int_leastxx*int_fast 的用例。如果你必须存储这样的整数,最快的可能不是最好的,没有什么可以阻止 sizeof(int_fast32_t) 变得不合理的大,由于缓存实际上可能使它比int_least32_t 慢。
  • 感谢您更新您的答案,这个stackoverflow.com/a/13424208/3144964
【解决方案2】:

我刚刚意识到 OP 只是询问int_fast##_t 而不是int##_t,因为后者是可选的。但是,我会保持答案跳跃它可能对某人有所帮助。


我会添加一些东西。固定大小的整数对于为其他语言构建 API 非常重要(甚至是必须的)。例如,当您想要 pInvoke 函数并将数据从 .NET 托管代码中的本机 C++ DLL 传递给它们时。在 .NET 中,int 保证为固定大小(我认为是 32 位)。因此,如果您在 C++ 中使用 int 并且它被认为是 64 位而不是 32 位,这可能会导致问题并减少包装结构的序列。

【讨论】:

    猜你喜欢
    • 2017-09-12
    • 2021-12-01
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多