我读到 GCC 支持
long long int
类型,该类型要求至少为 64 位宽。但它如何在只有 32 位宽的 CPU 上进行数学运算呢?
编译器将综合使用多个 CPU 指令来执行运算的数学运算(或使用函数调用)。例如,加法运算将添加
long long
值的低阶分量(低位字),然后将该运算的进位送入对 long long
的高阶字进行加法运算。 .
所以以下 C 代码:
long long a;
long long b;
long long c;
// ...
c = a + b;
可能由如下所示的指令序列表示:
mov eax, [a.low] ; add the low order words
add eax, [b.low]
mov edx, [a.high] ; add the high order words,
adc edx, [b.high] ; including the carry
mov [c.low], eax
mov [c.high], edx
如果您考虑一下,早在
long long
出现之前,8 位和 16 位系统的编译器就必须对 16 和/或 32 位值执行此类操作。
在内部,类型由高位字和低位字表示,例如:
struct long
{
int32 highWord;
uint32_t lowWord;
}
编译器需要知道它是 32 位还是 64 位环境,然后选择数字的正确表示 - 如果是 64 位,则可以在本机完成,如果是 32 位,编译器必须处理之间的数学运算高/低字。
如果您查看 math.h,您可以看到用于此目的的函数,并自己使用它们。另外,请注意小端和大端之间的区别(参见 wiki),其用法取决于操作系统。
说架构是 32 位(或 64 位或其他)通常只是处理器能力的近似值。通常你只用这个数字来引用指针的宽度,算术可能会有很大不同。例如,x86 架构具有 32 位指针,大多数算术在 32 位寄存器中执行,但它也对一些基本的 64 位操作具有本机支持。
另外,您不应该认为标准整数类型具有某些规定的宽度。特别是 long long 至少为 64 位,但可能更宽。如果您想确定宽度,请使用 typedef int32_t、int64_t。
如果您想知道 gcc(或任何其他编译器)使用 long long 做什么,您必须查看特定目标平台的规范
如果您有可访问的 32 位系统,则只需编译和测试就足够容易了。 gcc 有一个标志
-S
可以打开汇编语言输出。这是它在我的 32 位英特尔上产生的结果:
// read two long longs from stack into eax:edx and ecx:ebx
movl 32(%esp), %eax
movl 36(%esp), %edx
movl 24(%esp), %ecx
movl 28(%esp), %ebx
// a+b
addl %ecx, %eax
adcl %ebx, %edx
// a-b
subl %ecx, %eax
sbbl %ebx, %edx
// etc
很可能是作为一个类,而不是原生的。同样的方式,任何编译器都可以支持任何大数字集。