2014-10-04 55 views
4

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

+0

对于无符号类型,结果是“它应该是”以接收变量的大小为模。我的意思是:只有适合的位被存储;剩下的(如果有的话)被忽略。对于签名类型,结果是未定义的。 – wildplasser 2014-10-04 18:39:30

回答

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++?解释促销的理由。

0

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

3

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

事实上目的地左值x的分配x = expr;对是否有expr溢出没有影响。如果有,那么结果就是它是什么,不管x有多宽。

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

如果您已经添加了两个uint32_t值,那么可能会出现环绕(无符号操作产生超出无符号类型范围的结果时的指定行为),即使左值类型分配结果为uint64_t

+0

+1你和Jens从字面上回答我后,我实际上等着看有没有人会用更好的答案跳进来,我原本打算只发表评论。 – 2014-10-04 18:46:27

2

是,全部算术运算的宽度至少为int。因此,您的操作数首先转换为int,然后执行操作。就像在第一个例子中那样,结果然后被转换回分配的目标类型。

通常,使用窄类型进行算术不是一个好主意。尽可能避免这种情况,这只会让事情变得复杂。最好的办法是完全避免这些类型,除非你真的有问题需要存储大量的数字,例如