Integer Rank in C Type Conversions

In the C programming language, the concept of integer conversion rank provides a strict, standardized hierarchy that governs how operands of differing integer types are implicitly converted during expression evaluation. Whenever an operation involves mixed types, the compiler does not perform calculations on mismatched bit-widths or incompatible signedness arbitrarily. Instead, it relies on integer rank to dictate both integer promotions—elevating smaller types to standard machine-sized integers—and the "usual arithmetic conversions," which reconcile differing types into a single common type to ensure predictable and safe computation.

Every integer type in C is assigned a specific rank according to standard language rules. The basic hierarchy of signed types, listed from highest to lowest rank, is:

  1. long long int
  2. long int
  3. int
  4. short int
  5. signed char

Unsigned integer types share the exact same rank as their corresponding signed counterparts (for example, unsigned int has the same rank as signed int). The _Bool (or bool) type holds the lowest rank of all integer types. Standard char shares the same rank as signed char and unsigned char, regardless of whether the implementation treats plain char as signed or unsigned by default. Extended integer types, if provided by an implementation, are integrated into this hierarchy based on their precision.

Integer rank first governs the process of integer promotion, which is applied automatically to operands in unary and binary expressions. Any integer type with a rank strictly less than the rank of int and unsigned int (such as char, short, or bit-fields) is immediately promoted. If the original type's complete value range can be represented by a standard int, the value is converted to int; otherwise, it is converted to unsigned int. This step eliminates sub-int operations, standardizing the minimum working type at the machine level.

After integer promotions are applied, the compiler uses integer rank to determine the "usual arithmetic conversions" for binary operators when the operands still differ in type. The resolution follows a deterministic set of precedence rules:

  • Same Signedness: If both operands are signed or both are unsigned, the operand with the lower conversion rank is converted to the type of the operand with the higher rank. For example, in an operation between int and long int, the int is converted to long int.
  • Unsigned Rank Greater Than or Equal: If the unsigned operand has a conversion rank greater than or equal to the rank of the signed operand, the signed operand is converted to the type of the unsigned operand. For instance, in an expression combining int and unsigned int, the int is converted to unsigned int.
  • Signed Rank Greater With Full Representation: If the signed operand has a greater rank than the unsigned operand, and the signed type can represent all possible values of the unsigned type, the unsigned operand is converted to the signed type. For example, on a system where long is 64-bit and unsigned int is 32-bit, the unsigned int safely converts to long.
  • Signed Rank Greater Without Full Representation: If the signed operand has a higher rank but cannot represent all values of the unsigned operand (such as when both types have the same width, as often occurs with long and unsigned int on certain platforms), both operands are converted to the unsigned counterpart of the signed type (e.g., unsigned long).

Through these structured rules, integer rank ensures that implicit type coercion in C is consistent, preventing undefined behavior and minimizing data truncation across different hardware architectures.