在 int 上使用 __int16(或 int16_t)的优点/缺点

Posted

技术标签:

【中文标题】在 int 上使用 __int16(或 int16_t)的优点/缺点【英文标题】:Advantages/Disadvantages of using __int16 (or int16_t) over int 【发布时间】:2020-02-10 20:46:35 【问题描述】:

据我了解,int 使用的字节数取决于系统。通常,int 使用 2 或 4 个字节。

根据 Microsoft's documentation、__int8__int16__int32__int64 是 Microsoft 特定关键字。此外,__int16 使用 16 位(即 2 个字节)。

问题:使用__int16(或int16_t)有什么优势/劣势?例如,如果我确定我的整数变量的值永远不需要超过 16 位,那么将变量声明为 __int16 var(或 int16_t var)是否有益?

更新:我看到几个 cmets/answers 建议使用 int16_t 而不是 __int16,这是一个很好的建议,但并不是使用 __int16 的真正优势/劣势。 基本上,我的问题是,使用 16 位版本的整数而不是 int 节省 2 个字节的优点/缺点是什么?

【问题讨论】:

缺点:这是微软特有的。请改用C++11's fixed ranged integers。 如果不花钱的话,总是更喜欢跨平台解决方案而不是单平台解决方案。 @nada:这是明显的劣势。抱歉,如果我确定该程序将在 Windows 机器上运行,我忘了提及。更新了我的问题。 使用较小的类型可能是有益的,它也可能导致完全相反的结果。必要时进行基准测试。 @skm 可移植性仍然是一个问题,即使目标是 Windows。如果有人想用 MinGW 编译怎么办? 【参考方案1】:

使用这些类型的主要原因是确保变量在不同架构和编译器中的大小。我们称之为“代码可重用性”和“可移植性”

在更高级的现代语言中,所有这些都将由编译器/解释器/虚拟机/等处理。你不需要担心,但它有一些性能和内存使用成本。

当您遇到某种限制时,您可能需要优化所有内容。最好的例子是具有非常有限的内存大小并且以低频率工作的嵌入式系统。另一方面,有很多编译器具有不同的实现。其中一些将“int”解释为“16bit”值,而另一些解释为“32bit”。

例如,您通过通信系统接收特定的值流,您希望将它们保存在缓冲区或数组中,并且您希望确保输入数据始终被解释为 16 位注释。

【讨论】:

【参考方案2】:

如果你出于某种原因只需要一个较短的整数类型,它已经在语言中提供了 - 称为 short - 除非你知道你需要正好 16 位,否则真的没有充分的理由不坚持 不可知论 shortint 类型。广义的想法是这些类型应该与目标架构很好地保持一致(例如参见word)。

话虽如此,不需要使用平台特定类型(__int16),您可以使用标准类型:

int16_t

有关更多信息和标准类型,请参阅https://en.cppreference.com/w/cpp/types/integer

即使你仍然坚持__int16,你也可能想要一个 typedef 的东西。:

using my_short = __int16;

更新

您的主要问题是:

什么是优点/缺点 通过使用 16 位版本的整数而不是 int 来节省 2 个字节?

如果您有大量数据(根据经验,在至少大约 100.000-1.000.000 个元素的范围内) - 那么在使用更少的 CPU 缓存方面可能会节省整体性能.总的来说,使用较小的类型没有任何缺点——除了显而易见的类型——以及this answer中解释的可能的转换@

【讨论】:

呃,危险的......即使在今天,也有一些系统(通常是嵌入式系统),其中 short 和 int 具有相同的大小!如果您有最低范围要求并且希望可移植,则通常最好使用显式范围(如果您关心性能,可能更喜欢快速而不是修复变体)。 @Aconcagua short 和 int 确实有最小值 - 你需要充分意识到这一点! 也不是。但是你需要小心使用它们,特别是如果你想要便携的话。定义了最低要求后,两者都可以用 16 位覆盖(实际上,我什至已经使用了具有 CHAR_BIT == 16 和 sizeof(int) == sizeof(short) == sizeof(char)!的系统)。如果您为某些非常特定的系统编写代码,而您知道int 具有 32 位,这不是问题。但是对于可移植代码,您没有这种保证。 另一个例子:你知道你需要 32 位,但你有一个相当大的数组(如另一个答案所示),所以你也不想使用更多。 OK,int 可能还不够,那么好吧,那我们选择long。然后我们在 64 位 linux 上编译,结果发现我们使用了两倍的内存。发生了什么? long 是 64 位... 重点是:如果您对数据类型有特定(最小?)大小要求,来自<cstdint> 的固定范围整数,或者,如果另外性能很重要,它们的fast 变体,允许您以更安全的方式编写高效的可移植代码。【参考方案3】:

视情况而定。

在 x86 上,基本类型通常按大小对齐。所以 2 字节类型将在 2 字节边界上对齐。当您有多个这些短变量时,这很有用,因为您将节省 50% 的空间。这直接转化为更好的内存和缓存利用率,因此理论上更好的性能。

另一方面,对短于int 的类型进行算术运算通常涉及扩大到int 的转换。因此,如果您对这些类型进行大量算术运算,使用 int 类型可能会带来更好的性能 (contrived example)。

因此,如果您关心代码关键部分的性能,profile 可以确定使用某种数据类型是更快还是更慢。 p>

一个可能的经验法则是 - 如果您受内存限制(即您有很多变量,尤其是数组),请使用尽可能短的数据类型。如果没有 - 不要担心并使用 int 类型。

【讨论】:

关心展示转换发挥作用的示例(例如在godbolt上)? - 我不认为这可能是一个问题 - 与缓存节省相比有多大? '因此,如果您关心代码关键部分的性能,请对其进行分析 [...]' - 这样做很可能会发现瓶颈实际上在其他地方。 .. ;) @darune - 我发布的任何示例都可能被视为做作。不过,这里是a example。热代码中的缓存通常不是问题,在这种情况下,第二个版本肯定会更慢。【参考方案4】:

节省 2 个字节几乎是不值得的。但是,节省数千字节。如果你有一个包含整数的大数组,使用小整数类型可以节省相当多的内存。这会导致代码更快,因为使用的内存越少,接收到的缓存未命中就越少(缓存未命中是性能的主要损失)。

TL;DR:这在大型数组中是有益的,但对于 1-off 变量毫无意义。

这些的第二个用途是用于处理二进制文件和消息。如果您正在读取使用 16 位整数的二进制文件,那么如果您可以在代码中准确地表示该类型,那将非常方便。

顺便说一句,不要使用微软的版本。使用标准版本 (std::int16_t)

【讨论】:

存在std::int16_t的实现支持是可选的限制。 @Peter 这难道不是一个优势吗?如果无法支持,实现通常不会提供该类型,因此如果我们需要它,无论如何我们都会遇到麻烦。编译失败然后立即将我们推到那里,而不是退回到某种不想要的大小...... @Aconcagua - 不反对。简单地指出这是一个需要注意的限制。 嗯,使用二进制 16 位值从二进制 16 位源中读取既方便又危险。也许没问题,如果您可以依赖文件和 CPU 的相同字节顺序,否则,还有一个问题需要考虑...... 嗯,模ntohs,是的。使用更大的整数也不能解决字节顺序问题。

以上是关于在 int 上使用 __int16(或 int16_t)的优点/缺点的主要内容,如果未能解决你的问题,请参考以下文章

处理代码重新定义 int 类型(uint16_t、int16_t 等)和 Boost 不喜欢它

NEON:将 int8x16_t 拆包成一对 int16x8 并将一对 int16x8_t 打包成 int8x16_t

g ++ inlined在调用always_inline“int _rdrand16_step()”时失败

为啥 INT_FAST16_MAX 被定义为 INT32_MAX (VS 2015)?

动态整数大小:int64_t、int32_t、uint32_t 等

写入 int vs uint16_t 时的内存填充