64位系统的整数大小差异(与旧的32位pc系统混淆)

时间:2011-09-18 19:07:54

标签: windows 64-bit int abi

几个月前,我给自己买了一台带有64位Windows的cpu intel i7-2630qm笔记本电脑。在这个系统下练习我的编程技巧时,我在整数大小方面遇到了一些差异,这让我觉得这可能是由于我新的64位系统。

我们来看一下代码。

C代码:

#include <stdio.h>

int main(void)
{
    int num = 20;

    printf("%d %lld\n" , num , num);

    return 0;
}

问题:

1。)我记得在购买这台新笔记本电脑之前,这意味着我仍在使用我的旧32位系统,当我运行此代码时,程序将打印整数20而有些随机由于%lld说明符,它旁边的数字。

2.)但是当我使用我的新笔记本电脑时,这种现象不再发生,它将正确地打印两个整数,即使我将变量num更改为short类型。

3.)它是否在64位系统上,有一个新的整数提升,当它被用作参数时会将int提升为很长时间?或者可以提升short整数当作为参数传递时,long long也是64位?

4.)除此之外,我对16位系统非常困惑,int将是16位,当它位于32位系统时它将是32位。但是为什么它不是64位时才变成64位?

=============================================== =================================== 插件:

1.)我选择“控制台程序(64位)”作为我在IDE上的项目,同时使用我的新笔记本电脑,但在我的32位旧PC系统上使用“控制台程序”。

2.)我使用int运算符在“控制台程序(64位)”项目下检查sizeof的大小,它返回32位,而short仍保留16位。唯一的变化是long类型,它是64位,long long仍然保持其通常的64位大小。

4 个答案:

答案 0 :(得分:3)

您看到了这种副作用,因为x64代码的调用约定是不同的。 32位x86代码中的函数参数在堆栈上传递。 printf()函数将从堆栈中读取一个不属于激活帧的单词。它包含值0的几率非常低。

在x64代码中,函数的前4个参数通过cpu寄存器传递,而不是堆栈。 64位寄存器的高位字偶然为零的几率非常好。通过以前的64位操作留在那里,使用小数字。但肯定不能保证。

尝试推断未定义行为的已定义行为否则无用。除了试图猜测语言是如何为您机器中的核心实现的。有更好的资源。学习适用于编译器的机器代码是一个很好的捷径。与体面的调试器一起向您展示如何将C代码转换为机器代码。机器代码没有未定义的行为。

答案 1 :(得分:1)

您描述的所有内容都特定于您的编译器使用的任何规范以及您所使用的平台(long保证与int的大小至少相同):< / p>

维基百科条目:

long long

int

c99标准旨在通过添加特定类型来结束这种模糊性; int32_tuint64_t等。还有一个定义u_int32_t等的POSIX规范。

修改:我错过了关于printf()的问题,抱歉。正如@nos在您的问题的评论中指出的那样,将long long以外的内容传递给%lld会导致未定义的行为。这意味着它将做什么没有押韵或理由;独角兽自发出现并不是不可能的。

哦 - 在我知道的每个编译器和操作系统上,int是32位。改变它有可能打破依赖于32位的东西。

答案 2 :(得分:1)

我现在无法访问Windows 64位编译器,但我猜是以下内容。

您的问题不是关于整数提升,而是关于如何将参数从函数调用者传递给被调用函数。这超出了C规范,但有趣的是知道。

在32位中,所有参数都被分为32位块,因为所有寄存器都可以保存32位。所以在这种情况下,我们有以下堆栈布局:

[ 32-bit format string pointer ][ num as 32-bit ][ num as 32-bit ] junk...

在64位中,所有参数都被分为64位块,因为所有寄存器都可以保存64位。所以堆栈将包含以下内容:

[ 64-bit format string pointer ][ num as 64-bit ][ num as 64-bit ] junk...

保持32位值的64位寄存器的高32位方便地设置为零。

因此,当printf读取64位数时,它将在32位平台上加载相当于两个32位寄存器,但只有一个64位寄存器,高位清零, 64位平台。

答案 3 :(得分:1)

(1和2)如前所述,这种情况下的行为是未定义的,因此允许编译器因任何原因或根本没有任何理由而表现不同。

(3)允许编译器将int定义为64位,在这种情况下,不需要进行升级,因为所讨论的所有变量都是相同的大小。但它几乎肯定不会。

(4)在大多数或所有64位编译器上,int是32位。这是因为int已经长达32位,程序员已经开始期待它并且改变它会破坏现有的代码。据我所知,这不是标准的正式部分,但它是那些更难以改变的事实标准之一。 : - )