是否有理由在跨平台代码中使用 C++11 的 std::int_fast32_t 或 std::int_fast16_t 而不是 int ?
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::int32_t
和 std::int64_t
,它们是可选的,因此对于编写跨平台代码而言并不是最佳选择。然而,我们也得到了类型的非可选变体:例如"fast" 变体,例如std::int_fast32_t
和 std::int_fast64_t
,以及 "smallest-size" 变体,例如std::int_least32_t
,它们都至少是指定的位数。
我正在处理的代码是基于 C++11 的跨平台库的一部分,它支持在最流行的 Unix/Windows/Mac 编译器上进行编译。现在出现的一个问题是,用 C++11 固定宽度整数类型替换代码中现有的整数类型是否有优势。
使用 std::int16_t
和 std::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_t
和 std::uint_fast32_t
是否有意义?
int
在当前的计算机和编译器上可以是 16 位、32 位甚至 64 位。将来,它可能会更大(比如 128 位)。
如果您的代码没有问题,那就继续吧。
如果您的代码仅经过测试并使用 32 位整数,请考虑使用 int32_t
。然后代码将在编译时失败,而不是在 运行 在没有 32 位整数的系统上 运行 时失败(这在今天非常罕见)。
int_fast32_t
是您至少需要 32 位,但您非常关心性能的情况。在将 32 位整数加载为 64 位整数,然后在繁琐的过程中向下移位回 32 位整数的硬件上,int_fast_32_t
可能是 64 位整数。这样做的代价是在不知名的平台上,您的代码的行为非常不同。
如果您不在此类平台上进行测试,我建议您不要这样做。
在构建时出现问题通常比在 运行 时出现问题要好。如果您的代码实际上是 运行 在需要这些功能的一些不起眼的处理器上,那么 然后 修复它。 "you probably won't need it" 规则适用。
保守一点,在你没有测试的硬件上产生早期错误,当你需要移植到所述硬件时,做可靠所需的工作和测试。
简而言之:
当且仅当您已经在 int 大小不同的平台上 测试了 您的代码(并将继续测试它)并且您已经展示性能改进值得未来维护。
使用具有常见 ##
大小的 int##_t
意味着您的代码将无法在您未测试过的平台上编译。这很好;未经测试的代码是不可靠的,不可靠的代码通常比无用更糟糕。
如果不使用 int32_t
,而使用 int
,您的代码有时会有 32 位的 int
,有时会有 64 位的整数(理论上更多),有时int
是 16。如果你愿意在每个这样的 int
中测试和支持每个这样的案例,那就去做吧。
请注意,int_fast##_t
的数组可能存在缓存问题:它们可能大得不合理。例如,int_fast16_t
可能是 64 位。几千或几百万个数组单独使用可能很快,但由于它们的体积大而导致的缓存未命中可能会使它们整体变慢;并且东西被换成更慢的存储的风险增加了。
int_least##_t
在这些情况下会更快。
这同样适用于网络传输和文件存储的数据,除了 network/file 数据通常必须遵循在 compiler/hardware 变化中保持稳定的格式这一明显问题之外.然而,这是一个不同的问题。
但是,在使用固定宽度整数类型时必须特别注意,int、long 等仍然具有与以前相同的宽度。整数提升仍然基于 int 的大小发生,这取决于您使用的编译器。代码中的整数将是具有相关宽度的 int 类型。如果您使用不同的编译器编译代码,这可能会导致意外行为。更多详细信息:
我刚刚意识到 OP 只是询问 int_fast##_t
而不是 int##_t
因为后者是可选的。但是,我会保留答案,希望它能对某人有所帮助。
我想补充一点。固定大小的整数对于为其他语言构建 API 非常重要(甚至是必须的)。例如,当您想要 pInvoke
函数并在原生 C++ DLL 中从 .NET 托管代码向它们传递数据时。在.NET中,int
保证是一个固定大小(我认为是32位)。因此,如果您在 C++ 中使用 int
并且它被认为是 64 位而不是 32 位,这可能会导致问题并减少包装结构的序列。
在 C++11 中,我们提供了固定宽度的整数类型,例如 std::int32_t
和 std::int64_t
,它们是可选的,因此对于编写跨平台代码而言并不是最佳选择。然而,我们也得到了类型的非可选变体:例如"fast" 变体,例如std::int_fast32_t
和 std::int_fast64_t
,以及 "smallest-size" 变体,例如std::int_least32_t
,它们都至少是指定的位数。
我正在处理的代码是基于 C++11 的跨平台库的一部分,它支持在最流行的 Unix/Windows/Mac 编译器上进行编译。现在出现的一个问题是,用 C++11 固定宽度整数类型替换代码中现有的整数类型是否有优势。
使用 std::int16_t
和 std::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_t
和 std::uint_fast32_t
是否有意义?
int
在当前的计算机和编译器上可以是 16 位、32 位甚至 64 位。将来,它可能会更大(比如 128 位)。
如果您的代码没有问题,那就继续吧。
如果您的代码仅经过测试并使用 32 位整数,请考虑使用 int32_t
。然后代码将在编译时失败,而不是在 运行 在没有 32 位整数的系统上 运行 时失败(这在今天非常罕见)。
int_fast32_t
是您至少需要 32 位,但您非常关心性能的情况。在将 32 位整数加载为 64 位整数,然后在繁琐的过程中向下移位回 32 位整数的硬件上,int_fast_32_t
可能是 64 位整数。这样做的代价是在不知名的平台上,您的代码的行为非常不同。
如果您不在此类平台上进行测试,我建议您不要这样做。
在构建时出现问题通常比在 运行 时出现问题要好。如果您的代码实际上是 运行 在需要这些功能的一些不起眼的处理器上,那么 然后 修复它。 "you probably won't need it" 规则适用。
保守一点,在你没有测试的硬件上产生早期错误,当你需要移植到所述硬件时,做可靠所需的工作和测试。
简而言之:
当且仅当您已经在 int 大小不同的平台上 测试了 您的代码(并将继续测试它)并且您已经展示性能改进值得未来维护。
使用具有常见 ##
大小的 int##_t
意味着您的代码将无法在您未测试过的平台上编译。这很好;未经测试的代码是不可靠的,不可靠的代码通常比无用更糟糕。
如果不使用 int32_t
,而使用 int
,您的代码有时会有 32 位的 int
,有时会有 64 位的整数(理论上更多),有时int
是 16。如果你愿意在每个这样的 int
中测试和支持每个这样的案例,那就去做吧。
请注意,int_fast##_t
的数组可能存在缓存问题:它们可能大得不合理。例如,int_fast16_t
可能是 64 位。几千或几百万个数组单独使用可能很快,但由于它们的体积大而导致的缓存未命中可能会使它们整体变慢;并且东西被换成更慢的存储的风险增加了。
int_least##_t
在这些情况下会更快。
这同样适用于网络传输和文件存储的数据,除了 network/file 数据通常必须遵循在 compiler/hardware 变化中保持稳定的格式这一明显问题之外.然而,这是一个不同的问题。
但是,在使用固定宽度整数类型时必须特别注意,int、long 等仍然具有与以前相同的宽度。整数提升仍然基于 int 的大小发生,这取决于您使用的编译器。代码中的整数将是具有相关宽度的 int 类型。如果您使用不同的编译器编译代码,这可能会导致意外行为。更多详细信息:
我刚刚意识到 OP 只是询问 int_fast##_t
而不是 int##_t
因为后者是可选的。但是,我会保留答案,希望它能对某人有所帮助。
我想补充一点。固定大小的整数对于为其他语言构建 API 非常重要(甚至是必须的)。例如,当您想要 pInvoke
函数并在原生 C++ DLL 中从 .NET 托管代码向它们传递数据时。在.NET中,int
保证是一个固定大小(我认为是32位)。因此,如果您在 C++ 中使用 int
并且它被认为是 64 位而不是 32 位,这可能会导致问题并减少包装结构的序列。