当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布尔值、字符和整数,它说(强调mine):

如果int可以表示原始类型的所有值,则该值将转换为int;否则,它将转换为无符号整数。这些被称为整数promotions.48)所有其他类型都不受整数促销的影响。

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

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

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

事实上,分配x = expr;的目的左值xexpr中是否存在溢出无关。如果有,那么无论x有多宽,结果都是什么

在您的示例中,应用"整数提升",并且在int操作数之间进行计算。这意味着没有溢出。第6.3.1.1:2条C11中描述了整数促销。

如果您添加了两个uint32_t值,则可能存在回绕(当无符号运算产生超出无符号类型界限的结果时的指定行为),即使要分配给结果的左值的类型是uint64_t

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

通常,用窄类型进行算术根本不是一个好主意。尽可能避免这种情况,这只会使事情变得复杂。最好是完全避免这些类型,除非您在存储大型数字数组时遇到真正的问题,例如

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

相关内容

  • 没有找到相关文章

最新更新