我有以下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 :(得分: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或更大的数据类型,则更宽。