Edit: Changed the value for USHRT_MAX
as it was not conformant as shown by comments.
Imagine you have a fancy compiler where its integer type limits, as defined in limits.h are:
#define INT_MAX 2147483647 /* Typical 32-bit system value */
#define USHRT_MAX 2147483647 /* ***Edited***, original question had 2000000000 */
And in my application I have the following code:
unsigned short a = 1500000000;
unsigned short b = 1500000000;
unsigned short c;
c = a + b;
As far as I know, what will happen in the last instruction will be:
a
. As int
can take all values of unsigned short
, a
gets promoted to int
.b
gets promoted to int
.int
types.int
. Undefined Behavior due to paragraph 6.5/5.Is my reasoning correct? Does this really invoke undefined behavior, or where did I go wrong? Note that my code only works with unsigned types, and a result applying the modulus for unsigned integers could be expected due to legal overflow on unsigned types.
If the answer to the previous question is "yes, undefined behavior", this happened for a legal conformant compiler. So, can you say that the application code I posted is incorrect? Do all non-explicitly-casted small unsigned integer additions potentially invoke undefined behavior?
12.2. 1 Basics of Integer Overflow In contrast, the C standard says that signed integer overflow leads to undefined behavior where a program can do anything, including dumping core or overrunning a buffer. The misbehavior can even precede the overflow.
"A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type."
Unsigned integers are used when we know that the value that we are storing will always be non-negative (zero or positive). Note: it is almost always the case that you could use a regular integer variable in place of an unsigned integer.
An int is signed by default, meaning it can represent both positive and negative values. An unsigned is an integer that can never be negative. If you take an unsigned 0 and subtract 1 from it, the result wraps around, leaving a very large number (2^32-1 with the typical 32-bit integer size).
It is not possible for USHRT_MAX to be defined as 2000000000. The maximum values of unsigned integers must be in the form: 2^n-1:
6.2.6.2 Integer types
- For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N value bits, each bit shall represent a different power of 2 between 1 and 2 N−1 , so that objects of that type shall be capable of representing values from 0 to 2 N − 1 using a pure binary representation; this shall be known as the value representation. The values of any padding bits are unspecified.
Let's say USHRT_MAX is 2^31-1 and INT_MAX is 2^31-1.
In this case the variables a
and b
will be promoted to type int
, due to integer promotions, and the result of the signed addition will overflow.
gcc is smart enough to treat the addition of two unsigned short variables as unsigned when they are assigned to an unsigned short.
Nevertheless, for full portability the code should be:
c = a + 0u + b;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With