1

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

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

4.)除此之外,我对一件事很困惑,在 16 位系统上,int将是 16 位,而在 32 位系统上将是 32 位。但为什么不变成 64-当它在 64 位时位?

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

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

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

4

4 回答 4

3

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

在 x64 代码中,函数的前 4 个参数通过 cpu 寄存器而不是堆栈传递。64 位寄存器的高位字偶然为零的几率是相当大的。由之前处理小数字的 64 位操作留下。但肯定不能保证。

试图推理出未定义行为的已定义行为是没有用的。除了试图猜测语言是如何为您机器中的核心实现的。有更好的资源。学习适用于您的编译器的机器代码是一个极好的捷径。与体面的调试器一起向您展示您的 C 代码是如何被翻译成机器代码的。机器代码没有未定义的行为。

于 2011-09-18T20:01:01.810 回答
1

您所描述的所有内容都特定于您的编译器使用的任何规范和您所在的平台(除了long保证至少与 相同的大小int):

维基百科条目:

长长的

整数

c99 标准试图通过添加特定类型来结束这种歧义。int32_t, uint64_t, 等等。还有一个 POSIX 规范定义了u_int32_t, 等等。

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

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

于 2011-09-18T19:14:09.653 回答
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 位寄存器。

于 2011-09-18T19:36:38.003 回答
1

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

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

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

于 2011-09-18T19:43:52.383 回答