问题
I have the following C code:
uint8_t firstValue = 111;
uint8_t secondValue = 145;
uint16_t temp = firstValue + secondValue;
if (temp > 0xFF) {
return true;
}
return false;
This is the alternative implementation:
uint8_t firstValue = 111;
uint8_t secondValue = 145;
if (firstValue + secondValue > 0xFF) {
return true;
}
return false;
The first example is obvious, the uint16_t
type is big enough to contain the result.
When I tried the second example with the clang
compiler on OS/X, it correctly returned true. What happens there? Is there some sort of temporary, bigger type to contain the result?
回答1:
The operands of +
are promoted to larger types, we can see this by going to draft C99 standard section 6.5.6
Additive operators which says:
If both operands have arithmetic type, the usual arithmetic conversions are performed on them.
and if we go to 6.3.1.8
Usual arithmetic conversions it says:
Otherwise, the integer promotions are performed on both operands.
and then we go to 6.3.1.1
Boolean, characters, and integers which says (emphasis mine):
If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.
So both operands of +
in this case will be promoted to type int for the operation, so there is no overflow.
Note, Why must a short be converted to an int before arithmetic operations in C and C++? explains the rationale for promotions.
回答2:
The first example is obvious, the uint16_t type is big enough to contain the result.
In fact the destination lvalue x
for the assignment x = expr;
has no bearing on whether there is an overflow in expr
. If there is, then the result is what it is regardless of how wide x
is.
In your example, “integer promotions” apply and the computation is done between int
operands. This means that there is no overflow. Integer promotions are described in C11 in clause 6.3.1.1:2.
If you had been adding two uint32_t
values, then there could have been wrap-around (the specified behavior when an unsigned operation produces a result that is out of bounds for the unsigned type), even if the type of the lvalue to assign to result to was uint64_t
.
回答3:
Yes, all arithmetic is done in a type that has at least the width of int
. So your operands are first converted to int
and then the operation is performed. As in your first example, the result is then converted back to the target type of the assignment.
Usually it is not a good idea at all to do arithmetic with narrow types. Avoid that when you can, it only complicates things. Best is to avoid these types completely, unless you have a real problem to store large arrays of numbers, e.g.
回答4:
In C, intermediate results are done as at least int
, wider if the input type is long or some larger datatype.
来源:https://stackoverflow.com/questions/26195811/what-happens-when-a-integer-overflow-occurs-in-a-c-expression