在32位CPU上,"整数"类型比"短"类型更有效吗?

Jor*_*mer 9 architecture cpu integer 32-bit cpu-architecture

在32位CPU上,整数是4个字节,短整数是2个字节.如果我正在编写一个使用许多数值的C/C++应用程序,它总是符合短整数的提供范围,那么使用4字节整数或2字节整数会更有效吗?

我听说它建议4字节整数更有效,因为它适合从内存到CPU的总线带宽.但是,如果我将两个短整数相加,那么CPU是否会在一次通过中并行封装两个值(从而跨越总线的4字节带宽)?

Rob*_*ker 14

如果您有大量数字,那么请使用最小的数字.由于您获得了两倍的缓存密度,因此使用16位短路阵列而不是32位整数将更有效.与高速缓存未命中的成本相比,CPU在32位寄存器中处理16位值所需的任何符号扩展的成本几乎可以忽略不计.

如果您只是在与其他数据类型混合的类中使用成员变量,那么它就不那么明确,因为填充要求可能会消除16位值的任何节省空间的好处.


MrZ*_*bra 13

是的,你肯定应该在32位CPU上使用32位整数,否则它可能最终屏蔽掉未使用的位(即,它总是以32位进行数学运算,然后将答案转换为16位)

它不会同时为您执行两个16位操作,但如果您自己编写代码并且您确定它不会溢出,则可以自己完成.

编辑:我应该补充一点,它在某种程度上取决于你对"效率"的定义.虽然它能够更快地执行32位操作,但您当然会使用两倍的内存.

如果这些用于某个内部循环的中间计算,则使用32位.但是,如果你是从磁盘读取它,或者即使你只需要为缓存未命中付费,那么使用16位整数仍然可能更好.与所有优化一样,只有一种方法可以知道:对其进行分析.

  • 应该注意的是,C99 中的 stdint.h 具有 int_fastN_t 和 uint_fastN_t 类型,其中 N 是 8/16/32/64(但并非总是可用)。boost 对 c++ 有一个等价物,而 g++ 也倾向于包含 stdint.h。哪些应该是最快的类型,所需的大小最小。 (2认同)

DGe*_*try 8

如果您使用"很多"整数值,则处理中的瓶颈可能是内存带宽.16位整数更紧密地包含在数据缓存中,因此可以获得性能.

如果你是对大量数据进行数字处理,你应该阅读Ulrich Drepper的"每个程序员应该知道的内容".专注于第6章,关于最大化数据缓存的效率.


Mec*_*cki 5

32 位 CPU 是一种通常在内部对 32 位值进行操作的 CPU,但这并不意味着在对 8/16 位值执行相同操作时它会变慢。例如,x86 仍然向下兼容到 8086,可以对寄存器的小数部分进行操作。这意味着即使寄存器是 32 位宽,它也只能在该寄存器的前 16 位或前 8 位上运行,并且根本不会减速。这个概念甚至被 x86_64 所采用,其中寄存器是 64 位,但它们仍然只能在前 32、16 或 8 位上运行。

此外,x86 CPU 总是从内存加载整个缓存行(如果尚未在缓存中),并且缓存行无论如何都大于 4 字节(对于 32 位 CPU,而不是 8 或 16 字节),因此从内存加载 2 字节的速度与从内存中加载 4 个字节。如果处理来自内存的许多值,16 位值实际上可能比 32 位值快得多,因为内存传输较少。如果缓存行是 8 字节,则每个缓存行有四个 16 位值,但只有两个 32 位值,因此当使用 16 位整数时,每四个值有一次内存访问,使用 32 位整数时,每两个值有一​​个,导致处理大型 int 数组的传输次数增加两倍。

其他 CPU,例如 PPC,不能只处理寄存器的一小部分,它们总是处理整个寄存器。然而,这些 CPU 通常具有特殊的加载操作,允许它们例如从内存加载 16 位值,将其扩展为 32 位并将其写入寄存器。后来他们有一个特殊的存储操作,从寄存器中获取值,只将最后 16 位存储回内存;两种操作都只需要一个 CPU 周期,就像 32 位加载/存储需要的那样,因此也没有速度差异。由于 PPC 只能对寄存器执行算术运算(与 x86 不同,它也可以直接对内存进行运算),因此无论您使用 32 位整数还是 16 位整数,这个加载/存储过程都会发生。

唯一的缺点是,如果在只能对完整寄存器进行操作的 32 位 CPU 上链接多个操作,则上次操作的 32 位结果可能必须在执行下一个操作之前“缩减”为 16 位,否则结果可能不正确。不过,这样的削减只是一个 CPU 周期(一个简单的 AND 运算),并且编译器非常擅长确定何时确实需要这样的削减,以及何时省略它不会对最终结果产生任何影响,所以这样的缩减不会在每条指令之后执行,只有在确实不可避免的情况下才会执行。一些 CPU 提供了各种“增强”指令,这使得这样的削减变得不必要,我在生活中见过很多代码,我曾预料到这样的削减,但查看生成的汇编代码,

因此,如果您期望这里有一般规则,我将不得不让您失望。既不能肯定 16 位操作与 32 位操作一样快,也不能肯定地说 32 位操作总是更快。这还取决于您的代码究竟对这些数字做了什么以及它是如何做到的。我见过某些 32 位 CPU 上的 32 位操作比具有 16 位操作的相同代码更快的基准测试,但是我也已经看到相反的情况。即使从一种编译器切换到另一种编译器或升级您的编译器版本,也可能会再次扭转局面。我只能说以下内容:谁声称使用 shorts 比使用 ints 慢得多,请提供该声明的示例源代码并命名他用于测试的 CPU 和编译器,因为在过去的大约 10 年里,我从未经历过这样的事情。可能在某些情况下,使用 ints 可能快 1-5%,但低于 10% 的任何东西都不是“重要的”,问题是,在某些情况下是否值得浪费两倍的内存仅仅是因为它可能会买你2% 性能?我不这么认为。

  • x86 处理器会遭受“部分寄存器停顿”,例如,如果您写入 `ax` 然后尝试从 `eax` 读取。如果您混合使用 16 位和 32 位操作,则需要注意一些事项。 (2认同)