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

我有以下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。 那里发生了什么? 是否有某种临时的 ,更大的类型来包含结果?

+的操作数被提升为更大的类型,我们可以通过草拟C99标准 6.5.6添加运算符来看到这一点:

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

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

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

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

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

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

注意, 为什么在C和C ++中的算术运算之前必须将short转换为int? 解释了促销的理由。

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

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

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

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

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

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

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