当C表达式中出现整数溢出时会发生什么情况?

当C表达式中出现整数溢出时会发生什么情况?,c,integer-overflow,integer-promotion,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 + secondVal

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

在C语言中,中间结果至少是
int
,如果输入类型是长的或某个更大的数据类型,中间结果会更宽

+
的操作数升级为更大的类型,我们可以通过转到第
6.5.6节
加法运算符来了解这一点,其中说明:

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

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

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

然后我们转到
6.3.1.1
Boolean、characters和integer,上面写着(我的重点):

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

因此,在本例中,
+
的两个操作数都将升级为int类型,这样就不会出现溢出

请注意,解释促销的基本原理

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

实际上,赋值的目标左值
x
x=expr
expr
中是否存在溢出无关。如果有,则无论
x
有多宽,结果都是这样

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

如果您添加了两个
uint32\u t
值,则可能存在环绕(当无符号操作生成的结果超出无符号类型的界限时的指定行为),即使要分配给结果的左值的类型是
uint64\u t
是,所有运算都是在宽度至少为
int
的类型中完成的。因此,首先将操作数转换为
int
,然后执行操作。与第一个示例一样,结果将转换回赋值的目标类型


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

对于无符号类型,结果是将接收变量的大小模化为“它应该是什么”。我的意思是:只存储适合的位;其余部分(如果有)将被忽略。对于签名类型,结果是未定义的。+1 you和Jens在我之后直接回答,我实际上在等着看是否有人会给出更好的答案,我原本只想留下评论。