64位机器中的C++ int vs long long
Posted
技术标签:
【中文标题】64位机器中的C++ int vs long long【英文标题】:C++ int vs long long in 64 bit machine 【发布时间】:2017-02-08 08:16:36 【问题描述】:我的电脑有 64 位处理器,当我查找 sizeof(int)
、sizeof(long)
和 sizeof(long long)
时,结果发现 int 和 long 是 32位,而 long long 是 64 位。我研究了原因,似乎流行的假设告诉 C++ 中的 int 适合机器的字长是错误的。据我了解,由编译器来定义大小,我的是 Mingw-w64。我研究的原因是了解如果使用小于字长的类型对速度有好处(例如,short vs int)或者如果它有负面影响。在 32 位系统中,一种流行的观点是:由于字长为 int,short 将被转换为 int,它会导致额外的位移等,从而导致性能下降。反对意见是缓存级别会有好处(我没有深入研究),使用 short 将有助于虚拟内存经济。所以,除了混淆这个困境之外,我还面临另一个问题。我的系统是 64 位的,不管我使用 int 还是 short ,它仍然会小于字长,我开始认为不会t 使用 64 位 long long 是有效的,因为它处于系统设计的水平。另外我读到还有另一个约束,即定义类型大小的操作系统库(ILP64,LP64)。在 ILP64 中,默认 int 是 64 位,与 LP64 相比,如果我使用支持 ILP64 的操作系统,它会加速程序吗?当我开始询问我应该使用哪种类型来加速我的 C++ 程序时,我面临着我没有专业知识的更深层次的主题,并且一些解释似乎相互矛盾。你能解释一下吗:
1) 如果最佳做法是在 x64 中使用 long long 以实现最佳性能,即使是 1-4 字节数据?
2) 使用小于字长的类型的权衡(内存赢vs额外操作)
3) 字和整数大小为 64 位的 x64 计算机是否有可能通过所谓的向后兼容性使用 16 位字大小来处理短的?或者它必须将16位文件转换为64位文件,并且可以这样做的事实定义了系统向后兼容。
4) 我们可以强制编译器将 int 设为 64 位吗?
5) 如何将 ILP64 集成到使用 LP64 的 PC 中?
6) 使用适用于其他编译器、操作系统和架构(32 位处理器)的上述问题的代码可能会出现什么问题?
【问题讨论】:
永远不要依赖标准数据类型来获得特定的大小。 C++11 对此有 fixed-width integer types。 (在 C++11 之前有编译器特定的类型) 您可以拥有 512 位 CPU,而 16 位int
仍然 100% 符合标准。为什么有人会这样做,我无法理解,但它仍然是合法的。
【参考方案1】:
1) 如果最佳实践是在 x64 中使用 long long 以实现最佳性能,即使是 1-4 字节数据?
不-实际上它可能会使您的表现变得更糟。例如,如果您使用 64 位整数,而您本来可以使用 32 位整数,那么您只是将必须在处理器和内存之间发送的数据量增加了一倍,并且内存速度要慢几个数量级。你所有的缓存和内存总线都会以两倍的速度崩溃。
2) 使用小于字长的类型的权衡(内存赢与额外操作)
一般来说,现代机器性能的主要驱动因素是需要存储多少数据才能运行程序。一旦程序的工作集大小按顺序超过寄存器、L1 高速缓存、L2 高速缓存、L3 高速缓存和 RAM 的容量,您将看到显着的性能悬崖。
此外,如果您的编译器足够聪明,能够弄清楚如何使用处理器的向量指令(也称为 SSE 指令),那么使用较小的数据类型可能会更有利。现代矢量处理单元足够智能,可以将 8 个 16 位短整数与两个 64 位长整数塞入同一个空间,因此您一次可以执行四倍的操作。
3) 字和整数大小为 64 位的 x64 计算机是否有可能通过所谓的向后兼容性使用 16 位字大小来处理短字节?或者必须把16bit的文件转成64bit的文件,能做到就说明系统是向后兼容的。
我不确定你在这里问什么。一般来说,64 位机器能够执行 32 位和 16 位可执行文件,因为那些早期的可执行文件使用了 64 位机器潜力的一个子集。
硬件指令集通常向后兼容,这意味着处理器设计人员倾向于添加功能,但很少删除功能。
4) 我们可以强制编译器将 int 设为 64 位吗?
所有编译器都有相当标准的扩展,允许您处理固定位大小的数据。比如头文件stdint.h
声明了int64_t
、uint64_t
等类型。
5) 如何将 ILP64 集成到使用 LP64 的 PC 中?
https://software.intel.com/en-us/node/528682
6) 在其他编译器、操作系统和架构(32 位处理器)中使用适应上述问题的代码可能会出现什么问题?
通常,编译器和系统足够聪明,可以弄清楚如何在任何给定系统上执行您的代码。然而,32 位处理器将不得不做额外的工作来处理 64 位数据。换句话说,正确性应该不是问题,但性能才是问题。
但通常情况下,如果性能对您来说真的很重要,那么您无论如何都需要针对特定的架构和平台进行编程。
澄清请求:非常感谢!我想澄清问题:1。你说这对记忆不好。让我们以 32 位 int 为例。当你将它发送到内存时,因为它是64位系统,对于一个想要的整数0xee ee ee ee,当我们发送它时它不会变成0x ee ee ee ee + 32个其他位吗?当字长为 64 位时,处理器如何发送 32 位? 32 位是所需的值,但它不会与 32 位未使用的位组合并以这种方式发送吗?如果我的假设是正确的,那么内存没有区别。
这里有两件事要讨论。
首先,您讨论的情况不会发生。处理器不需要为了适当地使用它而将 32 位值“提升”为 64 位值。这是因为现代处理器具有不同的访问模式,能够适当地处理不同大小的数据。
例如,64 位 Intel 处理器有一个名为 RAX 的 64 位寄存器。但是,通过将其称为 EAX,同样的寄存器可以在 32 位模式下使用,甚至在 16 位和 8 位模式下也可以使用。我从这里偷了一张图表:
x86_64 registers rax/eax/ax/al overwriting full register contents
1122334455667788
================ rax (64 bits)
======== eax (32 bits)
==== ax (16 bits)
== ah (8 bits)
== al (8 bits)
在编译器和汇编器之间生成正确的代码,以便正确处理 32 位值。
其次,当我们谈论内存开销和性能时,我们应该更加具体。现代内存系统由磁盘、主内存 (RAM) 和通常两个或三个缓存(例如 L3、L2 和 L1)组成。可以在磁盘上寻址的最小数据量称为页面,,页面大小通常为 4096 字节(尽管并非必须如此)。然后,可以在内存中寻址的最小数据量称为 cache line, 通常远大于 32 或 64 位。在我的计算机上,缓存行大小为 64 字节。处理器是唯一在字级及以下实际传输和寻址数据的地方。
因此,如果您想更改驻留在磁盘上的文件中的一个 64 位字,那么,在我的计算机上,这实际上需要您将 4096 字节从磁盘加载到内存中,然后将 64 字节从内存加载到L3、L2 和 L1 缓存,然后处理器从 L1 缓存中获取单个 64 位字。
结果是字长对内存带宽没有任何意义。但是,您可以将这些 32 位整数中的 16 个放在可以打包这些 64 位整数中的 8 个的相同空间中。或者您甚至可以在同一空间中放置 32 个 16 位值或 64 个 8 位值。如果您的程序使用大量不同的数据值,您可以通过使用必要的最小数据类型来显着提高性能。
【讨论】:
@UserRR 你有一个 64 位寄存器和一个 64 位总线,但缓存和 RAM 仍然只是位行。如果指定 32 位,则使用 32 位。 这个答案的努力远远超过了这个问题的努力。太棒了。 也许这是一个复杂的问题,需要大量信息才能完成。 我仍然不明白的是,为什么人们通常建议使用 4 字节整数而不是 2 字节短整数,理由是 4 字节是处理器的自然字长,因此通常会产生最多最佳性能。但是,您在上面指出,在当今的 64 位处理器世界中,您不想在任何地方使用 8 字节整数。你如何调和这两个概念?请注意,这里我纯粹是在谈论性能而不是内存占用。 @SiddharthaGandhi 我认为通常不建议使用 4 字节整数。它恰好是许多编译器的默认整数大小。对于只有几个变量的程序,此答案中的考虑因素无关紧要。然而,处理大量数据的程序员绝对会关心并为他们的应用程序选择适当大小的数字类型。我认为 4 字节变量很常见,因为 2 字节变量对于许多用途来说往往太小,根据符号的不同限制为 0-65,000 或 -32,000-32,000。以上是关于64位机器中的C++ int vs long long的主要内容,如果未能解决你的问题,请参考以下文章
在 64 位 Windows 上 long 的位大小是多少?