Integer promotion: comparisons

This may be something basic, but I lost a bit of time last week trying to find a bug at work, so I thought it was worth mentioning it.

When comparing signed and unsigned expressions of the same size, the compiler produces what it might be unexpected results. Suppose you have this code:

#include <stdio.h>

int
main (void)
{
  unsigned short int a = -12;
  signed short int b = -12;

  printf ("%s\n", (a == b) ? "OK" : "failed");

  return 0;
}

Here, you would probably expect an “OK” output, but surprisingly you get “failed“. Why is this? If you know about integer promotion, you may skip to the end if you don’t want to follow all the process.

Fortunately, I received a copy of K&R last week, so I started digging into the issue to try to understand why this was happening.

About equality operators, K&R section A7.10 reads

The equality operators follow the same rules as the relational operators…

Section A7.9, about relational operator, reads

The usual arithmetic conversions are performed on arithmetic operands…

So, how these arithmetic conversions work?

This is also clearly explained in K&R section A6.5 (the same rules apply to the C99 standard, section 6.3.1.8, Usual arithmetic conversions). The part that interests us is after having evaluated all the real type conversions, when it says

Otherwise, the integer promotions are performed on both operands…

So, before performing the comparison of our operands, both undergo integer promotion. Integer promotion (K&R, section A6.2) says that

If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int.

An int can represent all the values of our operands, so after the integer promotion is performed, both operands have int type. Having a look back to our operands, we know that the a variable holds the value 0xFFF4, and after applying the integer promotion, it maintains the value. The same happens with variable b, that holds 0xFFFFFFF4 to represent -12. Clearly, both values are different and the check fails.

At the end of K&R section A6.5 this is explicitly explained

The new rules are slightly more complicated, but reduce somewhat the suprises that may occur when an unsigned quantity meets signed. Unexpected results may still occur whan an unsigned expression is compared to a signed expression of the same size.

Basically, what’s going on here, is that both variables undergo integer promotion. b is signed, and it is sign-extended. This sign-extension is maintained due to the integer promotion.

Note, that this issue does not occur with 32-bit values, as both operands would be “0xFFFFFFF4″.

So, be careful when comparing unsigned and signed types.

About these ads

10 Responses to “Integer promotion: comparisons”

  1. Shwetank Gupta Says:

    Can u plz tell me ….how a 16bit int [b here] start representing value corresponds to 32 bit? It seems bizarre to me as i m not able to dig it out with my present understanding. Kindly update it to me if anybody is aware of the same.

    • aleix Says:

      This is what integer promotion does. As both operands are converted to 32-bits in order to perform the comparison, the 16-bit signed integer is converted to a 32-bit signed integer. Signed integer follow two’s complement representation, so the sign is extended.

      So, you are comparing 0x0000FFF4 with 0xFFFFFFF4, which are different.

      There would be no problem if the comparison was done directly with 16-bit values.

  2. Shwetank Gupta Says:

    There is some confusion:
    Acc to my understanding in case of integer promotion signed int becomes corresponding unsigned int(sign bit start using in forming value)
    Now in this case both signed-unsigned int are of same size(16-bit).
    Why they have to convert in 32 bits for the comparison??

    One question on the same:
    “There would be no problem if the comparison was done directly with 16-bit values.”
    If the size of int be 32 bits while size of unsigned int be 16bits then also integer value will just corresponding the value of the possible unsigned int??

    • aleix Says:

      > Acc to my understanding in case of integer promotion signed int becomes
      > corresponding unsigned int(sign bit start using in forming value)

      Not always, check C99 standard section 6.3.1.8.

      > Now in this case both signed-unsigned int are of same size(16-bit).
      > Why they have to convert in 32 bits for the comparison??

      This is what the standard says (6.3.1.1):


      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.)

      The integer promotions preserve value including sign.

      This is what’s happening, both operands are converted to ints.

      > If the size of int be 32 bits while size of unsigned int be 16bits then also integer
      > value will just corresponding the value of the possible unsigned int??

      I’m not sure if I undertand this, but in this case the 16 bit value would be converted to int.

  3. Shwetank Gupta Says:

    Sorry, but i again have a query:
    >>I’m not sure if I undertand this, but in this case the 16 bit value >>would be converted to int.
    Again, with my understandings integer promotion only talks about promotion for signed integer and not for unsigned one. So, the value should remain of 16-bit.
    But we can confirm d same by running a testcase.

    >>The integer promotions preserve value including sign.
    Is that mean event after integer promotion signed int will retain its sign bit and not consider it as a part of value.
    Lets see this loop:
    unsigned int j = 6;
    int i;
    int flag = 0;
    for(i = -1;i < j; i++)
    {
    ……….printf("No integer promotion");
    ……….flag = 1;
    ……….break;
    }
    if(!flag)
    {
    printf("Integer promotion");
    }

    Now in this case "i" will be treated as 0xffffffff and not not consider MSB bit as a sign bit. We should have a messsage : "Integer promotion"

    Let me clear :)

    PS: I have just written the code so it might not be intact as such.

    • aleix Says:

      Yes, in the example you get “Integer promotion”. Here both operands are converted to unsigned int, following the standard:

      “Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.”

      So,

      1. We need to widen short values.
      2. We perform arithmetic conversions.

      For the 16-bit case (in the post):
      1. We follow 6.3.1.1 to widen both operands to int (preserving the sign for the signed short int).
      2. Then we have two int values that do not match.

      For the 32-bit case (your example):
      1. We do not need to widen any operand.
      2. Both operands are converted to unsigned int.

      Hope this helps.

  4. Shwetank Gupta Says:

    I go through this corresponding section in K&R … n it seems ur explanation is inline with it.
    But i would admire…if u give ur remarks on my last query.
    Thankx a lot in advance.

  5. Appa Rao Maiskar Says:

    I didnt understood the correct meaning of the words “original type” in the sentence

    > “if int can represent all the values of the original type”.

    could u plz explain with examples for both

    int representing values of original type and
    int not representing values of original type.

  6. aleix Says:

    This blog has been moved to http://hacks-galore.org/aleix/blog

    Please, add comments there.

  7. Diva Says:

    you can find some more details in the below link,”http://javadomain.in/clearly-explained-int-vs-integer/”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: