在x86_64模式下,寄存器中无法容纳64位数字

Yur*_*que 2 c c++ assembly gcc cpu-registers

我在这里的PC上有一个Intel处理器,它以64位模式x86_64运行,如果我使用字寄存器或使用某些标志优化功能,则寄存器的大小为64位,该变量往往放在寄存器中,但是,如果我将值放在32位以上,则编译器会抱怨,即我的int不是64位,为什么会发生这种情况?如果将变量放在寄存器中,那不是64位,我什至没有得到它的内存地址?也就是说,它甚至没有放置在堆栈上。

#include <stdio.h>

int main(void) {

    register int x = 4294967296;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译:

gcc example.c -o example -Wall -Wextra

输出:

警告:隐式常量转换[-Woverflow]寄存器int x = 4294967296中溢出;

Pet*_*des 8

C register关键字不执行任何操作来覆盖您选择的C类型的宽度。 int是所有32位和64位x86 ABI(包括x86-64 System V和Windows x64)中的32位类型。(long在Windows x64上也是32位,但在Linux / Mac /其他所有x86-64 1上都是64位。)

一个register int仍然是int,受所有的限制INT_MAXINT_MIN以及符号溢出是未定义的行为。 它不会将您的C源代码转换为可移植的汇编语言。

使用registerjust可以告诉编译器,即使在调试模式下,也可以将变量保留在寄存器的下半部分中。


如果一个寄存器有64位,为什么int的约定应为32位

int之所以是32位,是因为没有人希望int在64位计算机上将数组变成64位,而缓存占用量却是原来的两倍。

我不知道int= 的任何C实现int64_t,甚至在x86-64之外。即使是DEC Alpha(积极使用64位,并从头开始为64位设计),我认为仍然使用32位int。

使int32位从16个增长到有意义的32位机时,因为16位是“太小”的时候。(但是请记住,ISO C仅保证int至少16位。如果您需要更多,则在真正可移植的程序中,最好使用longint_least32_t。)

但是对于大多数程序而言,32位“足够大”,并且64位计算机始终具有快速的32位整数,因此int当从32位迁移到64位计算机时,请保持32位不变。

在某些计算机上,不是很好地支持16位整数。例如,uint16_t在MIPS上实现包装到16位将需要额外的AND指令。因此,int在那里制作16位类型将是一个糟糕的选择。

在x86上,您可以仅使用16位操作数大小,并在复制时使用movzx而不是mov,但是int在32位计算机上将其设为32位是“正常的”,因此x86 32位ABI都选择了该大小。

当ISA从32位扩展到64位时int,与16-> 32情况不同,没有理由使性能变宽。(同样,在这种情况下,请short保留16位,因此即使在C99 stdint.h存在之前,也都有16位和32位整数的类型名)。

在x86-64上,默认的操作数大小仍为32位。mov rax, rcxvs.需要一个额外的前缀字节(REX.W)mov eax, ecx,因此32位的效率稍高。另外,在某些CPU上64位乘法略慢,即使在当前的Intel CPU上,64位除法也比32位慢得多。 在x86-64中使用32位寄存器/指令的优势


此外,如果编译器int32_t要提供int32_t所有可选的内容,则需要它们的原始类型。(固定宽度2的补码类型是可选的,与之不同的是int_least32_t等等不能保证是2的补码或没有填充。)

具有16位short和64位的编译器int 可能具有特定于实现的类型名称,就像__int32它们用作int32_t/ 的typedef一样uint32_t,因此此参数不是总的显示次数上限。但这很奇怪。

当从16增长到32时,将其更改int为比ISO C最小值更宽是有意义的,因为您仍将short16位作为名称。(此参数不是很好,因为您确实long在32位系统上使用了32位整数的名称。)

但是,当增长到64位时,您希望某种类型成为32位整数类型。(并且long不能比窄int)。 char/ short/ int/ long(或long long)覆盖所有4个可能的操作数大小。 int32_t不能保证在所有系统上都可用,因此如果希望每个人都想要32位带符号整数,则希望每个人都使用它不是可移植代码的可行选择。


脚注1

您可以用任何一种方法争论是long32位还是64位类型更好。微软选择将其保留为32位意味着使用的结构布局long可能不会在32位和64位代码之间改变(但是如果包含指针,它们会改变)。

ISO C long至少必须为32位类型(实际上,它们是根据可以表示的最小值和最大值来定义它的,但是在其他地方,它们确实要求整数类型是带有可选填充的二进制整数)。

无论如何,某些代码long之所以使用是因为它需要32位类型,但不需要64位类型。在许多情况下,更多的点并不是更好,只是不需要它们。

在像x86-64 System V这样的单个ABI中,总是很长与指针具有相同的宽度是不方便的,但是由于可移植代码始终需要使用unsigned long longuint64_tuint_least64_tuintptr_t取决于使用情况,因此可能是一个错误x86-64系统V已选择64位长。

OTOH,对于本地人来说,更广泛的类型有时可以通过在索引指针时避免符号扩展来保存指令,但是有符号溢出是未定义的行为这一事实通常会使编译器int在方便时在asm中扩展。

  • 而且,当然,我们都忽略了register的“真正”副作用-您不能使用标记为register的变量的地址。&lt;g&gt; (2认同)