我一直想知道这样的代码是如何运作的:
int a = 10;
int b = 20;
double c = a * b;
如果整数太大以至于a*b
大于可以存储在整数类型变量中的最大值,那该怎么办?编译器会注意到目标类型可以包含更大的值并首先将值转换为double
,还是乘法只会流过/回绕?
答案 0 :(得分:2)
当乘以两个整数值时,编译器本身永远不会将结果转换为浮点类型。也就是说,如果您将两个int
值相乘,结果也将是int
值。
所以,你的代码有效的是:
int a = 10;
int b = 20;
int tmp = a * b; // Result is actually an int
double c = (double)tmp; // Convert to a double.
因此,只有在无法存储在int中时,结果才会溢出。转换和分配到double
只能在计算结果后才能完成。
答案 1 :(得分:1)
答案是否定的。编译器不会将整数转换为双精度,因为编译器不运行任何代码。当程序执行时,整数将被乘法(并且可能溢出)并且结果将存储在'c'中,但'c'仅为双精度的事实意味着它足够大以保持结果。在放入'c'之前,溢出就已经发生了。
如果编译器能够更改数据类型,则意味着编译器不仅可以通过更改数据类型来影响最终的程序大小,还可以在代码的其他部分中弄乱数据类型期望。例如,如果您希望对一个整数进行位移,可能会发生不好的事情,但是在运行时,由于编译器决定更改您的数据类型,因此您需要进行双位移位。恐怖!
答案 2 :(得分:0)
乘法的结果将由usual arithmetic conversions确定,并且只考虑乘法本身的操作数,来自草案C ++标准:
*和/的操作数应具有算术或未范围的枚举类型; %的操作数应该有 整数或无范围的枚举类型。通常的算术转换是在操作数上执行的 并确定结果的类型。
如果结果无法用转换后的类型表示,那么它将调用未定义的行为:
如果在评估表达式期间,结果未在数学上定义或不在范围内 其类型的可表示值,行为未定义
因此您应该在操作之前检测到溢出并进行相应处理,请参阅Will gcc skip this check for signed integer overflow?
答案 3 :(得分:0)
如果整数太大而
a*b
大于最大值,该怎么办? 值可以存储在整数类型的变量中。
有符号整数溢出是未定义的行为。
编译器是否会注意到目标类型可以包含更大的值 并首先将值转换为
double
,或者将乘法转换为double
只是流过/环绕?
由于它未定义,因此允许编译器执行任何操作。这包括在{{1}}中进行计算,忽略溢出并返回底层硬件返回的任何内容,格式化硬盘,让你的猫怀孕,或介于两者之间。
大多数编译器可能会在大多数情况下忽略它,并使用“overflow is UB”来优化代码,其余时间会大幅增加。 SO上有一个很好的例子:Why does integer overflow on x86 with GCC cause an infinite loop?