The term promotion is applied in the C language to any type change in which an object is converted from a smaller to a larger type (e.g. int to long or float to double). However the term integral promotion has a special meaning and describes the silent conversion of smaller integral types to type int or unsigned int when an expression is evaluated.
Integral promotion should not be confused with balancing. Balancing occurs when two operands of different types must be converted to the same type in order to perform some operation. For example if an int and a long are added together, the int is always converted to a long and the result of the operation is of type long.
However integral promotion can take place when operands are of the same type. For example, when two signed chars are added together, both are converted to type int before addition and the result of the operation is of type int. This process is known as integral promotion and it occurs even with unary operators such as "-" or "~".
The rules of integral promotion say that:
A char, short, bit-field (all signed or unsigned) or an enum value is converted to an int if an int is able to represent all values of the original type, otherwise the value is converted to unsigned int.
In practice this means that the value of the original object is usually converted to an int but possibly to an unsigned int if the original data type is unsigned and of the same size as an int. For example in an implementation with an 8 bit char, a 16 bit short and a 32 bit int, all chars and shorts will be promoted to signed int values. However if both short and int are only 16 bits, an unsigned short will be promoted to an unsigned int.
For most of the time, integral promotion is of little significance; but there are occasions when failure to understand the concept can have interesting or dangerous consequences.
Assuming an 8 bit char, a 16 bit int and a 32 bit long, consider the following:
ucx = 0xFE; uca = ucx << 4; /* Result of shift is truncated */ sia = ucx << 4; /* Result of shift is preserved */
uca and sia will contain different values. When an unsigned char is shifted, it first undergoes integral promotion to a signed int and the result is an integer value. The first statement truncates the result; the second preserves it.
Now consider the following code:
uia = 0xF123; ula = uia << 4; /* Result of shift is truncated */
The result of the shift in this case always involves a loss of the high order bits. Conversion from unsigned int to unsigned long is performed after the shift operation in order to perform the assignment.
This example is a little contrived, but illustrates some interesting issues:
if (uca < -2) /* Always false */ ... if (uia < -2) /* Usually true ! */ ...
Both comparisons are clearly flawed insofar as an unsigned quantity can never be negative. The first can be described as degenerate, i.e. it always yields the value false. However in the second statement, the negative constant of type int actually gets converted to a large unsigned int value because of the rules involved in balancing expressions, and so the result will probably be true ! This anomaly arises from the fact that in the first example, uca is promoted to a signed int and therefore no balancing of operands is required.