我在我的电脑上有一个Intel处理器,它以64位模式x86_64运行,如果我使用字寄存器或使用某些标志优化功能,则寄存器的大小为64位,该变量往往放在寄存器中,但是,如果我将值设置为高于32位,则编译器会抱怨,即我的int不是64位,为什么会发生这种情况?如果将变量放在寄存器中,那不是64位,我什至没有得到它的内存地址?也就是说,它甚至没有放置在堆栈上。
#include <stdio.h>
int main(void) {
register int x = 4294967296;
return 0;
}
编译:
gcc example.c -o example -Wall -Wextra
输出:
warning: overflow in implicit constant conversion [-Woverflow] register int x = 4294967296;
最佳答案
C register
关键字不执行任何操作来覆盖您选择的C类型的宽度。 int
是所有32位和64位x86 ABI(包括x86-64 System V和Windows x64)中的32位类型。 (long
在Windows x64上也是32位,但在Linux / Mac /其他x86-641上是64位。)
register int
仍然是int
,但必须遵守INT_MAX
,INT_MIN
和有符号溢出的所有限制,这些行为均未定义。 不会将您的C源代码转换为可移植的汇编语言。
使用register
只是告诉编译器,即使在 Debug模式下,也可以将变量保留在寄存器的下半部分中。
If a register has 64 bits, why should the convention of int be 32 bits
int
是32位的,因为没人希望int
的数组在64位计算机上成为64位,并且具有两倍的缓存占用空间。 我不知道
int
= int64_t
的任何C实现,即使在x86-64之外也是如此。即使是DEC Alpha(积极使用64位,并从头开始为64位设计),我认为仍然使用32位int。当
int
从16位机器增加到32位机器时,使其成为32位是有意义的,因为16位有时“太小”。 (但是请记住,ISO C仅保证int
至少为16位。如果您需要更多,则在真正可移植的程序中,最好使用long
或int_least32_t
。)但是对于大多数程序而言,32位“足够大”,并且64位计算机始终具有快速的32位整数,因此当从32位计算机迁移到64位计算机时,
int
保持32位。 在某些计算机上,不是很好地支持16位整数。例如在MIPS上使用
uint16_t
实现到16位换行将需要额外的AND指令。因此,在那里将int
设置为16位类型将是一个糟糕的选择。在x86上,您可以仅使用16位操作数大小,并在复制时使用
movzx
而不是mov
,但是在32位计算机上int
为32位是“正常的”,因此x86 32位ABI都选择了该选项。当ISA从32位扩展到64位时,与16-> 32情况不同,没有零性能的原因使
int
更宽。 (在那种情况下,short
仍保留16位,因此即使在C99 stdint.h
存在之前,也都有16位和32位整数的类型名)。在x86-64上,默认的操作数大小仍为32位。
mov rax, rcx
与mov eax, ecx
相比,需要额外的前缀字节(REX.W),因此32位的效率稍高。而且,在某些CPU上,64位乘法略慢,即使在当前的Intel CPU上,64位除法也比32位慢得多。 The advantages of using 32bit registers/instructions in x86-64另外,如果编译器根本想提供可选的
int32_t
,则需要int32_t
的原始类型。 (固定宽度2的补码类型是可选的,与int_least32_t
等不同,它不能保证是2的补码或没有填充。)带有16位
short
和64位int
的编译器可以具有特定于实现的类型名称,例如__int32
,它们用作int32_t
/ uint32_t
的typedef,因此此参数不是总的toptop。但这很奇怪。当从16增长到32时,将
int
更改为比ISO C最小值更宽是有意义的,因为您仍然将short
作为16位的名称。 (此参数不是很好,因为在32位系统上,确实有long
作为32位整数的名称。)但是,当增长到64位时,您希望某种类型成为32位整数类型。 (而且
long
不能比int
窄)。 char
/ short
/ int
/ long
(或long long
)涵盖所有4种可能的操作数大小。不一定保证_int32_t
在所有系统上都可用,因此,如果每个人都希望使用32位带符号整数,则希望每个人都使用它不是可移植代码的可行选择。脚注1 :
您可以用任何一种方法争论
long
是32位还是64位类型是否更好。微软选择将其保留为32位意味着使用long
的结构布局可能不会在32位和64位代码之间改变(但是如果包含指针,它们会改变)。ISO C要求
long
至少为32位类型(实际上,它们是根据可以表示的最小值和最大值来定义它的,但在其他地方,它们确实要求整数类型是带有可选填充的二进制整数)。无论如何,有些代码使用
long
,因为它需要32位类型,但不需要64位类型。在许多情况下,更多的比特并没有更好,只是不需要它们。在像x86-64 System V这样的单个ABI中,总是很长的长度与指针一样宽是不方便的,但是由于可移植代码始终需要根据用例使用
unsigned long long
或uint64_t
或uint_least64_t
或uintptr_t
,因此x86-64 System V选择64位长可能是一个错误。OTOH,对于本地人来说,更广泛的类型有时可以通过在索引指针时避免符号扩展来保存指令,但是有符号溢出是未定义的行为这一事实通常使编译器在方便时可以扩展asm中的
int
。
关于c++ - 在x86_64模式下,寄存器中无法容纳64位数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55100284/