views:

541

answers:

4

If I execute the following code in C:

#include <stdint.h>

uint16_t a = 4000;
uint16_t b = 8000;

int32_t c = a - b;

printf("%d", c);

It correctly prints '-4000' as the result. However, I'm a little confused: shouldn't there be an arithmetic overflow when subtracting a larger unsigned integer from the other? What casting rules are at play here? This question seems a bit noobish, so any references would be greatly appreciated.

+2  A: 

Both operands are promoted to int32_t during the subtraction. If the result had been larger than the maximum value for int32_t you would've seen overflow.

dirkgently
+2  A: 

The short answer is that these are all promoted to int during the subtraction. For the long answer, look at section 6.3.1.1 of the C standard, where it talks about integer promotions in arithmetic expressions. Relevant language from the standard:

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. All other types are unchanged by the integer promotions.

The details are in there, too, but they get pretty nasty.

tgamblin
+1  A: 

The issue is actually somewhat complicated. Operands of arithmetic expressions are converted using specific rules that you can see in Section 3.2.1.5 of the Standard (C89). In your case, the answer depends on what the type uint16_t is. If it is smaller than int, say short int, then the operands are converted to int and you get -4000, but on a 16-bit system, uint16_t could be unsigned int and conversion to a signed type would not happen automatically.

TrayMan
My reference is of course to the old standard. See tgamblin's response for C99. Though they say the same thing.
TrayMan
3.2.1.5 is for double/float/int/etc conversions. He's looking for integral (long/int/char/short/etc) promotions which is in 3.2.1.1 of that version of the standard. It's in 6.3.1.1 in the newer standard I linked to above.
tgamblin
He might also want 3.2.1.2 too (signed/unsigned ints)
tgamblin
Section 3.2.1.5 covers integer conversions too.
TrayMan
oh hm so it does. I guess it's got rules for longs and such too. There's an index item that points you to 3.2.1.1 for integral promotions.
tgamblin
Alright, so what if we extend the example to two uint32_t and one int64_t, assuming 32-bit int width?
Davorian
In that case, the subtraction is unsigned and overflows.
TrayMan
A: 

There is, in fact, an overflow but C does not tell you.

The overflow leaves a value that happens to be -4000 when interpreted as a signed integer. This works as designed on 2's complement machines.

Try to interpret the result as unsigned, and you'll notice that (u1-u2) evaluates to some seemingly unrelated number when u1 < u2.

Ingo