64 位系统的整数大小差异(与我的旧 32 位电脑系统混淆)
几个月前,我给自己买了一台带有 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
更改为类型short
。
3.)是否在64位系统上,有新的整数提升,当用作参数时,会将int
提升为long long?还是short
整数当作为参数传递时,可以提升为 64 位的 long long
吗?
4.)除此之外,我对一件事感到非常困惑,在 16 位系统上,int
将是 16 位,而在 32 位系统上它将是 32 位。但是为什么它在 64 位上时不变成 64 位?
=================================================== ================================= 插件:
1.)当我使用我的新笔记本电脑时,我在 IDE 上选择“控制台程序(64 位)”作为我的项目,但在我的 32 位旧 PC 系统上选择“控制台程序”。
2.)我使用 sizeof
运算符检查了“控制台程序(64 位)”项目下 int
的大小,它返回 32 位,而 short
仍然保持 16 位。唯一的变化是 long
类型,它是 64 位,并且 long long
仍然保持其通常的 64 位大小。
Few months ago i get myself a laptop with cpu intel i7-2630qm with a 64-bit windows. While practising my programming skils under this system , I encountered some difference in terms of integer size which makes me think that it's probably due to my new 64-bit system.
Let's take a look at a code.
The C Code :
#include <stdio.h>
int main(void)
{
int num = 20;
printf("%d %lld\n" , num , num);
return 0;
}
The Question :
1.) I remember before getting this new laptop , which mean that time i'm still using my old 32-bit system , when i run this code , the program will print the integer 20
while some random number next to it due to the %lld
specifier.
2.)But this phenomena no longer happen when i'm using my new laptop , it will instead print both integer correctly , even if i change the variable num
to type short
.
3.)Is it on a 64-bit system , there's new integer promotion which will promote int
to long long when it's use as an argument??Or is it short
integer can be promoted to long long
which is 64-bit too when pass as an argument??
4.)Besides that I'm quite confuse with one thing , on 16-bit system , int
would be 16-bit and it would be 32-bit when it's on a 32-bit system.But why isn't it become 64-bit when it's on a 64-bit??
==================================================================================
Addon :
1.)I choose "console program(64-bit)" as my project on the IDE while using my new laptop but "console program" on my 32-bit old PC system.
2.)I've check the size of int
under "console program(64-bit)" project using sizeof
operator and it returns 32-bit while short
still remain 16-bit.The only change is long
type , it's 64-bit and long long
still remain its usual 64-bit size.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您会看到此副作用,因为 x64 代码的调用约定有所不同。 32 位 x86 代码中的函数参数在堆栈上传递。 printf() 函数将从堆栈中读取不属于激活帧的字。它包含 0 值的可能性极低。
在 x64 代码中,函数的前 4 个参数通过 cpu 寄存器传递,而不是堆栈。 64 位寄存器的高位字偶然为零的可能性非常大。这是之前处理小数字的 64 位操作留下的。但肯定不能保证。
否则,尝试推理出未定义行为的已定义行为是没有用的。除了尝试猜测该语言是如何为您机器中的核心实现的。有更好的资源可以做到这一点。学习适用于您的编译器的机器代码是一个很好的捷径。与不错的调试器一起,向您展示 C 代码如何转换为机器代码。机器代码没有未定义的行为。
You are seeing this side-effect because the calling convention is different for x64 code. The function arguments in 32-bit x86 code are passed on the stack. The printf() function will read a word from the stack that isn't part of the activation frame. The odds that it contains a value of 0 are extremely low.
In x64 code, the first 4 arguments for a function are passed through cpu registers, not the stack. The odds that the high word of the 64-bit register is zero by chance are quite good. Left there by a previous 64-bit operation that worked with small numbers. But certainly not guaranteed.
Trying to reason out the defined behavior of undefined behavior is otherwise not useful. Other than trying to guess how the language is implemented for the core that's in your machine. There are better resources for that. Learning the machine code that's applicable to your compiler is an excellent shortcut. Together with the decent debugger that shows you how your C code got translated into machine code. Machine code has no undefined behavior.
我现在无法访问 Windows 64 位编译器,但我的猜测如下。
您的问题不是关于整数提升,而是关于参数如何从函数调用者传递到被调用函数。这超出了 C 规范,但了解它很有趣。
在 32 位中,所有参数都分为 32 位块,因为所有寄存器都可以保存 32 位。因此,在这种情况下,我们有以下堆栈布局:
在 64 位中,所有参数都分为 64 位块,因为所有寄存器都可以保存 64 位。因此,堆栈将包含以下内容:
保存 32 位值的 64 位寄存器的高 32 位被方便地设置为零。
因此,当 printf 读取 64 位数字时,它会在 32 位平台上加载两个 32 位寄存器,但在64 位平台。
I do not have access to an windows 64-bit compiler right now, but my guess is the following.
Your question is not about integer promotion, but regarding how parameters are passed from the function caller to the called function. This is beyond the C specification, but it is interesting to know.
In 32-bit, all parameters are divided into 32-bit blocks as all registers can hold 32 bits. So in this case we have the following stack layout:
In 64-bit, all parameters are divided into 64-bit blocks as all registers can hold 64 bits. So the stack will contain the following:
The upper 32 bits of the 64-bit registers holding 32-bit values are conveniently set to zero.
So when
printf
is reading a 64-bit number, it will load the equivalent of two 32-bit registers on a 32-bit platform but only one 64-bit register, with high bits cleared, on a 64-bit platform.(1 和 2) 如前所述,这种情况下的行为是未定义的,因此允许编译器出于任何原因或根本没有原因而采取不同的行为。
(3) 编译器可以将 int 定义为 64 位,在这种情况下不需要升级,因为所有相关变量的大小都相同。但几乎可以肯定不会。
(4) 在大多数或所有 64 位编译器上,int 是 32 位。这是因为 int 长期以来一直是 32 位,以至于程序员已经开始期待它,并且更改它会破坏现有代码。据我所知,这并不是标准的正式一部分,但它是更难改变的事实上的标准之一。 :-)
(1 and 2) As already stated, the behaviour in this situation is undefined, so the compiler is allowed to behave differently for any reason or indeed no reason at all.
(3) The compiler is allowed to define int as 64-bit, in which case no promotion would be necessary because all the variables in question would be the same size. But it almost certainly doesn't.
(4) On most or all 64-bit compilers, int is 32-bits. This is because int has been 32 bits for so long that programmers have come to expect it and changing it would break existing code. As far as I know this isn't officially part of the standard, but it's one of those de-facto standards that are even harder to change. :-)
您所描述的所有内容都特定于您的编译器使用的任何规范以及您所在的平台(除了
long
保证至少与int
大小相同):维基百科条目:
long long
int
c99 标准试图通过添加特定类型来结束这种歧义;
int32_t
、uint64_t
等。还有一个 POSIX 规范定义了u_int32_t
等。编辑: 我错过了关于
printf()
的问题,抱歉。正如 @nos 在您的问题的评论中指出的那样,将long long
以外的内容传递给%lld
会导致未定义的行为。这意味着它的作用没有任何规律或理由。独角兽自发出现并非不可能。哦 - 在我知道的每个编译器和操作系统上,
int
都是 32 位。改变它有可能破坏依赖于 32 位的东西。Everything you are describing is specific to whatever spec your compiler is using and the platform you are on (with the exception that
long
is guaranteed to be at least the same size asint
):Wikipedia entries:
long long
int
The c99 standard seeks to end this ambiguity by adding specific types;
int32_t
,uint64_t
, etc. There's also a POSIX spec that definesu_int32_t
, etc.Edit: I missed the question about
printf()
, sorry. As @nos points out in the comments on your question, passing something other than along long
to%lld
results in undefined behavior. This means there is no rhyme or reason as to what it will do; unicorns spontaneously appearing would not be out of the question.Oh - and on every compiler and OS I know,
int
is 32 bit. Changing that has the potential to break things that depend on it being 32 bit.