在C表达式中发生整数溢出时会发生什么?

时间:2014-10-04 18:23:19

标签: c integer-overflow integer-promotion

我有以下C代码:

uint8_t firstValue = 111;
uint8_t secondValue = 145;
uint16_t temp = firstValue + secondValue;
if (temp > 0xFF) {
    return true;
}
return false;

这是替代实施:

uint8_t firstValue = 111;
uint8_t secondValue = 145;
if (firstValue + secondValue > 0xFF) {
    return true;
}
return false;

第一个例子很明显,uint16_t类型足以包含结果。 当我在OS / X上使用clang编译器尝试第二个示例时,它正确返回true。那里发生了什么?是否有某种临时,更大的类型来包含结果?

4 个答案:

答案 0 :(得分:7)

+的操作数被提升为更大的类型,我们可以通过转到draft C99 standard部分6.5.6 添加运算符来看到这一点:

  

如果两个操作数都具有算术类型,则执行通常的算术转换   它们。

如果我们转到6.3.1.8 通常的算术转换,它会说:

  

否则,将对两个操作数执行整数提升。

然后我们转到6.3.1.1 布尔,字符和整数,其中写着(强调我的):

  

如果int可以表示原始类型的所有值,则该值将转换为int;   否则,它将转换为unsigned int。 这些称为整数   促销活动 .48)整数促销活动保持所有其他类型不变。

因此,在这种情况下,+的两个操作数都将被提升为类型 int ,因此没有溢出。

注意,Why must a short be converted to an int before arithmetic operations in C and C++?解释了促销的基本原理。

答案 1 :(得分:3)

  

第一个例子很明显,uint16_t类型足以包含结果。

实际上,作业x的目标左值x = expr;expr中是否存在溢出无关。如果有,那么结果就是它是什么,无论x有多宽。

在您的示例中,“整数提升”适用,计算在int个操作数之间完成。这意味着没有溢出。整数促销在第6.3.1.1节第2节中的C11中描述。

如果你一直在添加两个uint32_t值,那么可能有环绕(当无符号运算产生超出无符号类型的结果时指定的行为),即使类型也是如此分配给结果的左值是uint64_t

答案 2 :(得分:2)

是的,所有算术都是在宽度为int的类型中完成的。因此,您的操作数首先转换为int,然后执行操作。与第一个示例中一样,然后将结果转换回赋值的目标类型。

通常,使用窄类型进行算术并不是一个好主意。尽可能避免,只会使事情复杂化。最好是完全避免这些类型,除非你有一个真正的问题来存储大数字数组,例如

答案 3 :(得分:0)

在C中,中间结果至少为int,如果输入类型为long或更大的数据类型,则更宽。