8

This code prints B2

short a=-5;
unsigned short b=-5u;
if(a==b)
    printf("A1");
else
    printf("B2");

I read about integer promotion but it's still unclear to me, how does it work in the example here? Can someone thoroughly post the steps the compiler follows in widening/truncating the values?

Johnny Pauling
  • 12,701
  • 18
  • 65
  • 108
  • which compiler are you using? –  Mar 06 '13 at 19:06
  • [this](http://en.cppreference.com/w/cpp/language/implicit_cast) could be useful. – juanchopanza Mar 06 '13 at 19:07
  • Integer promotion only happens in the `a==b` expression there - is that all you're asking about? – Carl Norum Mar 06 '13 at 19:07
  • MSVC2012 but I'd like to know how a standard-following compiler would behave – Johnny Pauling Mar 06 '13 at 19:07
  • 1
    I'm not sure what you expected, it'll never be equal because `unsigned short b = -5u` will wrap around to `65531`. – Rapptz Mar 06 '13 at 19:09
  • 1
    possible duplicate of [unsigned becomes signed in if-statement comparisons?](http://stackoverflow.com/questions/4204327/unsigned-becomes-signed-in-if-statement-comparisons) – Bo Persson Mar 06 '13 at 19:13
  • See also [Usual Arithmetic Conversions from Stephan T. Lavavej on Channel 9](http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/Stephan-T-Lavavej-Core-C-7-of-n) – Thomas Mar 06 '13 at 19:43

3 Answers3

11

Let's walk through your code:

short a = -5;

a = -5, which fits into a short. So far so easy.

unsigned short b = -5u;

-5u means apply the unary - operator to the constant 5u. 5u is (unsigned int) 5, and the unary - does no promotion, so you end up with 4294967291 which is 2^32-5. (Update: I got this bit wrong in my original answer; see a test script which shows this version is correct here http://codepad.org/hjooaQFW)

Now when putting that in b, it is truncated to an unsigned short (2 bytes, usually), so b = 65531, which is 2^16-5.

if( a == b )

In this line, a and b are both promoted to ints so that the comparison can happen correctly. If they were promoted to shorts, b would potentially wrap around. If they were promoted to unsigned shorts, a would potentially wrap around.

So it's like saying if( (int) a == (int) b ). And a = -5, so (int) a = -5, and b = 65531, so (int) b = 65531, because ints are bigger than shorts.

Dave
  • 44,275
  • 12
  • 65
  • 105
  • I wouldn't say `-5u` makes no sense - it is well-defined by the standard. – Carl Norum Mar 06 '13 at 19:18
  • 3
    Um, `-5u` is perfectly sensible. It applies `-` to the integer constant `5u`. – Pete Becker Mar 06 '13 at 19:18
  • You hit a point I'm interested in: so BEFORE -5 gets stored in the short 'a' variable... its constant value is treated as an integer, right? I'm deeply interested in this point – Johnny Pauling Mar 06 '13 at 19:22
  • @PeteBecker Updated the answer to account for that; it hadn't occurred to me. And Johnny, yes, it is an integer. Or you can use 5l to make it a long, or 5ul to make it an unsigned long, for example. Also note that a good compiler will complicate this hugely, but not in a way that it's possible to notice. – Dave Mar 06 '13 at 19:23
  • @JohnnyPauling : -5 is converted to a signed int before it's assigned. It's then truncated to a short, but that's fine in this case. – teppic Mar 06 '13 at 19:25
  • The unary `-` will not cause any conversion of the `5u`. It will remain an `unsigned int`. Applying `-` to it will result in `UINT_MAX - 4`, then that is converted to `unsigned short`. – Daniel Fischer Mar 06 '13 at 20:44
  • 1
    @EricPostpischil I was responding to Dave: "and the unary `-` will promote this (I presume to a `long`) with value `-5`." – Daniel Fischer Mar 06 '13 at 21:20
  • @DanielFischer Seems you're right. I'm updating the answer again, – Dave Mar 06 '13 at 22:23
2
a == b

a and b are both promoted to int in the above expression.

unsigned short b=-5u;

In this declaration -5U is converted to unsigned short by the means of integer conversion (C99, 6.3.1.3p2 applies here) and becomes a large value.

(C99, 6.3.1.3p2) "Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type."

b value is then (unsigned short) ((unsigned int) USHRT_MAX + 1 -5) which is (unsigned short) 65531 if USHRT_MAX is (unsigned short) 65535.

So what you have is:

(short) -5 == (unsigned short) 65531

which is equivalent after integer promotion of both operands to:

-5 == 65531

which is equivalent to 0.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • re "On a two's complement system", well it is that way regardless of signed integer representation, because the holy standard requires that it be binary, and because 5 is very much smaller then than the minimum required range, and because the standard requires unsigned arithmetic to be modulo 2^n where n is the number of representation bits. So for, say, 32-bit `unsigned` and 16-bit `unsigned short` the expression `-5u` in itself yields the value 2^32-5, and then that value modulo 2^16 is necessarily 2^16-5. again, regardless of signed integer representation. – Cheers and hth. - Alf Mar 06 '13 at 19:18
  • @Cheersandhth.-Alf Agree, I removed this sentence just before your comment. I started with the *on a two's complement system* because I initially wanted to add information about the (no) representation change. – ouah Mar 06 '13 at 19:23
1

short to unsigned short is a conversion (thus having conversion rank)

short to int is a promotion (thus having promotion rank)

Promotions are preferred over conversions because of the ranking. Promotions occur during arithmetic and other operations. Conversions occur when merely storing one integral type inside another. Arithmetic ops can cause conversions as well as promotions, in order to coerce the types together. For another example:

unsigned int u = 2; 
int i = 2; 
u + i;

i is converted (not promoted) to unsigned.

Your value is converted to a larger value because it wraps around due to being unsigned. Then, they are promoted to int. Thus a != b because of this.