我知道当我将大于INT_MAX
的值分配给 int 变量时会发生溢出,但如果这个值也被大数除以会发生什么? 在下面的语句中 溢出int x = 3000000000/10000;
会发生?
如果表达式中的整数常量(文字)可以用 C 编译器支持的类型表示,并且具有正确的符号,则编译器将对它们执行正确的算术(由 C 标准定义)。如果结果可以用int
表示,则int x = expression;
将初始化x
以获得该值。
如果结果无法在int
中表示,则初始化的结果是实现定义的,根据C 2018 6.3.1.3 3。
如果整数常量不能以 C 编译器支持的具有正确符号的任何类型的形式表示,则 C 标准不会定义该行为,但编译器必须提供诊断消息(根据 6.4.4.1 6 和 6.4.4 3)。
您可以投射更大的数字,例如long long
,然后将结果转换回 int。这应该避免任何溢出。 所以像这样:https://stackoverflow.com/a/9047811 (只是你之后会通过int result = (int)((long long)(numerator)/(long long)(denominator))
将其转换回 int .
当我将大于 INT_MAX 的值分配给 int 变量时会发生溢出,
当常量在(unsigned) long long
内时不会发生溢出。 相反,这是超出int
范围的值的转换。 结果是定义了实现。
当整数类型的值转换为
_Bool
以外的另一个整数类型时,如果该值可以由新类型表示,则它保持不变。
...
否则,新类型是有符号的,并且无法在其中表示该值;结果要么是实现定义的,要么是实现定义的信号。C17dr 6.3.1.3
常见的实现定义行为是删除上位。
int some_int = 0x123456789A; // Out of range
printf("%dn"); --> possible outcome 0x3456789A as "878082202"
如果这个值也除以一个大数字会发生什么?会发生溢出吗?
不。 在这种情况下3000000000
是long
或long long
。 商的类型相同,但值为 300,000。 使用 32 位int
,可以很好地转换为值为 300,000 的int
。
int x = 3000000000/10000;
在这种情况下,在int x = 3000000000LL/10000;
中附加LL
没有区别。
在您的特定情况下:
int x = 3000000000/10000;
右侧表达式是一个常量,因此编译器 [至少gcc
] 在编译时解析除法,因此结果是300000
。(为此,编译器必须使用比内部int
更高的精度进行常数约简)
但是,如果您这样做:
int x = 3000000000;
x /= 10000;
你得到:-129496
[因此溢出]
那是因为x
第一行溢出[并变为负数]。
3000000000
仍然适合 32 位(无符号),因此您可以得到值0x0xb2d05e00
.请注意,MSB [符号位] 已设置。
而且,当您除以10000
时,除法将保留标志并产生:0xfffe0628
乍一看,这两个代码片段应该产生相同的结果。但是,他们没有,因为编译器必须遵循两步过程(即它不能将两个步骤组合在一起)。
否则,编译器会破坏其他依赖于截断等的代码:(例如舍入):
int x = 37;
x /= 10;
x *= 10;
你很幸运,因为3000000000
[正如我所说]适合unsigned int
.但是,如果你添加一个额外的 0(例如)30000000000
,编译器将标记它:
warning: overflow in conversion from ‘long int’ to ‘int’ changes value from ‘30000000000’ to ‘-64771072’ [-Woverflow]
int x = 30000000000;
^~~~~~~~~~~
所以,你真的不应该依赖一个具体的结果,如果你已经知道你正在做一些有问题/错误的事情。
下面是一个示例程序:
#include <stdio.h>
int
print_x(void)
{
int x = 3000000000/10000;
return x;
}
int
print_y(void)
{
int y = 3000000000;
y /= 10000;
return y;
}
int
print_z(void)
{
int z = 3000000000;
return z;
}
int
print_w(void)
{
int w = 30000000000;
return w;
}
int
main(void)
{
printf("x=%dn",print_x());
printf("y=%dn",print_y());
printf("z=%dn",print_z());
printf("w=%dn",print_w());
return 0;
}
这是程序输出:
x=300000
y=-129496
z=-1294967296
w=-64771072