Integer Promotion Rules in C Expressions
In the C programming language, integer promotion is an implicit type
conversion mechanism where integer types smaller than int
are automatically converted to int or
unsigned int during expression evaluation. This article
explains the exact rules governing integer promotion, the data types
affected, how promotion integrates into the Usual Arithmetic
Conversions, and how these rules influence arithmetic operations to
prevent unexpected truncation.
What is Integer Promotion?
Integer promotion is a specific subset of implicit type conversions in C. Whenever an expression requires an arithmetic operation, the C compiler evaluates small integer types by promoting them to a standard processing width—typically the native word size of the CPU—before performing the calculation.
This design choice ensures optimal performance on target hardware architectures and prevents accidental overflow during intermediate calculations involving types with narrow ranges.
The Core Integer Promotion Rule
The ISO C standard defines the fundamental rule of integer promotion as follows:
Whenever a value of a type with an integer conversion rank less than
the rank of int appears in an expression:
- Promoted to
int: If theinttype can represent all possible values of the original type, the value is converted to a signedint. - Promoted to
unsigned int: Ifintcannot represent all possible values of the original type, the value is converted to anunsigned int.
Affected Data Types
Types with an integer conversion rank lower than int
include:
_Bool(orbool)char,signed char, andunsigned charshort intandunsigned short int- Enumeration types (if their values fit within
intorunsigned int) - Integer bit-fields
Signed vs. Unsigned Behavior
Because most modern architectures define int as 32 bits
and short as 16 bits, a standard
unsigned short has a range of 0 to
65,535, while a signed int has a range of
-2,147,483,648 to 2,147,483,647. Because all
values of unsigned short fit comfortably within the
positive range of a 32-bit int, an
unsigned short promotes to a signed
int, not an unsigned int.
An unsigned short will only promote to an
unsigned int on platforms where
sizeof(short) == sizeof(int).
Contexts Where Integer Promotion Occurs
Integer promotions occur automatically in several contexts during C expression evaluation:
1. Unary Operators
Operands of unary operators undergo integer promotion independently:
- Unary plus (
+) and unary minus (-) - Bitwise NOT (
~)
unsigned char a = 0xFF;
// 'a' is promoted to a signed int before applying the bitwise NOT.
// Result of (~a) is 0xFFFFFF00 (assuming 32-bit int), not 0x00.
int result = ~a; 2. Bit-Shift Operators
In shift operations (<< and
>>), both operands are promoted independently using
the integer promotion rules. The resulting type of the expression is the
promoted type of the left-hand operand:
unsigned char x = 1;
// x is promoted to signed int, then shifted
int shifted = x << 8; // Valid, results in int with value 2563. Usual Arithmetic Conversions
For binary arithmetic operations (such as +,
-, *, /, %) and
relational comparisons (<, >,
==, etc.), integer promotions act as the mandatory first
phase of the Usual Arithmetic Conversions:
- Both operands undergo integer promotion.
- If the operands are still of different types, the common type is
determined using the following hierarchy:
- If either operand is
unsigned long long, convert the other tounsigned long long. - Else if either is
long long, convert the other tolong long. - Else if either is
unsigned long, convert the other tounsigned long. - Else if either is
long, convert the other tolong. - Else if either is
unsigned int, convert the other tounsigned int. - Otherwise, both operands remain
int.
- If either operand is
Practical Example: Intermediate Overflow Prevention
Integer promotions prevent intermediate truncation errors during multi-step arithmetic evaluations:
unsigned char a = 100;
unsigned char b = 50;
unsigned char c = 20;
// Step-by-step evaluation:
// 1. 'a' and 'b' are promoted to int.
// 2. (a * b) evaluates to 5000 (signed int), avoiding 8-bit overflow.
// 3. 'c' is promoted to int.
// 4. 5000 / 20 evaluates to 250 (signed int).
// 5. 250 is truncated back to fit into unsigned char 'd'.
unsigned char d = (a * b) / c; Without integer promotion, a * b would overflow an 8-bit
unsigned char (maximum value 255) and wrap around to
136, producing an incorrect final value of 6
instead of 250.