Saturday, July 2, 2011

Integer Promotions and Conversions in C

Suppose you have the following code:
#include <stdio.h>

int main()
{
    unsigned x = 1;
    char y = -1;

    if (x > y)
        printf("x > y\n");
    else
        printf("x <= y\n");

    return 0;
}
What does really happen here? Since we are dealing with integer types, first the integer promotions are applied, and then the arithmetic conversions are applied.

If char is equivalent to signed char:
  • char is promoted to int (Integer Promotions, ISO C99 §6.3.1.1 ¶2)
  • Since int and unsigned have the same rank, int is converted to unsigned (Arithmetic Conversions, ISO C99 §6.3.1.8)
If char is equivalent to unsigned char:
  • char may be promoted to either int or unsigned int:
    • If int can represent all unsigned char values (typically because sizeof(int) > sizeof(char)), char is converted to int.
    • Otherwise (typically because sizeof(char)==sizeof(int)), char is converted to unsigned.
  • Now we have one operand that is either int or unsigned, and another that is unsigned. The first operand is converted to unsigned.

The rules that are applied are the following:

Integer promotions: An expression of a type of lower rank that int is converted to int if int can hold all of the values of the original type, to unsigned otherwise.

Arithmetic conversions: Try to convert to the larger type. When there is conflict between signed and unsigned, if the larger (including the case where the two types have the same rank) type is unsigned, go with unsigned. Otherwise, go with signed only in the case it can represent all the values of both types.

Conversions between integer types(ISO C99 §6.3.1.3):
  • Conversion of an out-of-range value to an unsigned integer type is done via wrap-around (modular arithmetic).
  • Conversion of an out-of-range value to a signed integer type is implementation defined, and can raise a signal (such as SIGFPE).
Ranks: Every type has a rank. unsigned types have the same rank as the corresponding signed type. Ranks satisfy the following: char < short < int < long < long long.

Representation of integer types:
  • Signed types consist of sign bits, padding bits and value bits.
  • Unsigned types consists of padding bits and value bits.
  • An unsigned type has to have a number of value bits greater or equal to the number of value bits of its corresponding signed type.
Now we can rephrase part of the above as:
  • unsigned char may be promoted to either int or unsigned int:
    • If int can represent all unsigned char values (because the number of value bits of int >= number of value bits of unsigned char), unsigned char is converted to int.
    • Otherwise (because the number of value bits of int < number of value bits of unsigned char), unsigned char is converted to unsigned.
Borderline example: a system with an unsigned char type with 1 padding bit and 31 value bits, and an int type with 1 sign bit and 31 value bits would fall into the first condition (and be an exception to the previous rule of thumb using sizeof()).

No comments:

Post a Comment