C 为什么是1024*1024*1024*2!=1024*1024*1024*2

C 为什么是1024*1024*1024*2!=1024*1024*1024*2,c,integer-overflow,C,Integer Overflow,一开始,我写了一个演示来获得2G内存,但是我遇到了这样的问题,我不知道为什么,num1,num2,num3有什么不同 #include<stdio.h> int main(){ unsigned long num1 = 1024*1024*1024*2; unsigned long num2 = 1024*1024*1024*2.0; unsigned long num3 = 1024*1024*1024; num3 *= 2; printf(

一开始,我写了一个演示来获得2G内存,但是我遇到了这样的问题,我不知道为什么,num1,num2,num3有什么不同

#include<stdio.h>
int main(){
    unsigned long num1 = 1024*1024*1024*2;
    unsigned long num2 = 1024*1024*1024*2.0;
    unsigned long num3 = 1024*1024*1024;
    num3 *= 2;
    printf("num1:%lu\n num2:%lu\n num3:%lu\n", num1, num2, num3);
    return 0;
}

第一行,
无符号长num1=1024*1024*1024*2
,用
int
初始化
无符号长(
num1
)。计算
1024*1024*1024*2
具有类型
int
,因为所有值都是
int
文本。至少在其中一个上使用
UL
后缀,使其
无符号长

unsigned long num1 = 1024UL*1024*1024*2;
作为预防措施,您可以将后缀放在第一个值上,因为乘法具有从左到右的关联性。这样,所有这些乘法都是在类型为
unsigned long
的值之间进行的,而不是在类型为
int
的值之间进行的


至于其他两种方法的工作原理:第二行使用
double
初始化
num2
,在这种情况下,它具有足够的精度来生成正确的值;第三行用
int
初始化
num3
,但是
1024*1024*1024
可以用32位
int
表示(它是2^30,小于2^31-1)。之后的2的乘法是在一个
无符号长
上完成的,因此它可以按预期工作。

1024*1024*1024*2
此计算是使用
int
数据类型执行的,因为所有的文字都是or类型
int
。因此,你得到符号整数溢出,我猜它是未定义的(C++中它是未定义的行为,不确定C)。你得到警告吗?非常类似:这个代码给出警告:<代码>测试。C:在函数“Mead”中:Test.C:3:40:警告:表达式中的整数溢出[ Woverflow ]未签名的长NUM1=1024×1024×1024×2;<代码>始终启用警告。我得到了这个,但我不知道当时为什么,但我现在找到了答案,不管怎样,谢谢。UL是个好主意,但是
1024*1024*1024
仍然使用
int
数学计算。这会溢出16位
int
,这在嵌入式处理器中很常见,并且具有其他不太明显的常量。最好将铅常数设为
UL
1024*1024*2
因此所有的计算都是使用
无符号long
数学完成的。我知道,这是一个多么简单的解决方案!谢谢,这对我帮助很大。
unsigned long num1 = 1024UL*1024*1024*2;