Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

Usual arithmetic conversions are a standardized set of implicit type conversion rules applied to the operands of most binary operators in C to yield a common type (which may be a real or complex type) for the operation and its result. These rules establish a strict hierarchy evaluated sequentially based on type domain, integer conversion rank, and signedness. Phase 1: Floating-Point Resolution The compiler first checks for floating-point types. If either operand has a floating-point type, the other operand is implicitly converted to match, and no integer promotions are performed:
  • If either operand has type long double (or long double _Complex), the other operand is converted to long double (or the corresponding complex type).
  • Otherwise, if either operand has type double (or double _Complex), the other operand is converted to double (or the corresponding complex type).
  • Otherwise, if either operand has type float (or float _Complex), the other operand is converted to float (or the corresponding complex type).
Phase 2: Integer Promotions If neither operand has a floating-point type, integer promotions are applied to both operands. Any operand with an integer conversion rank lesser than int (such as char, signed char, unsigned char, or short), as well as bit-fields of type _Bool, int, signed int, or unsigned int, is promoted to int if int can represent all values of the original type. If int cannot represent all values, the operand is promoted to unsigned int. Phase 3: Integer Resolution After integer promotions, the compiler evaluates the promoted integer operands against the following rules, stopping at the first matching condition:
  1. Same Signedness: If both operands have the same signedness (both signed or both unsigned), the operand with the lesser integer conversion rank is converted to the type of the operand with the greater rank.
  2. Mixed Signedness (Unsigned Rank Dominates): If the operand with unsigned integer type has a rank greater than or equal to the rank of the type of the signed integer operand, the signed integer operand is converted to the type of the unsigned integer operand.
  3. Mixed Signedness (Signed Rank Dominates, Value Preserved): If the type of the signed integer operand can represent all of the values of the type of the unsigned integer operand, the unsigned integer operand is converted to the type of the signed integer operand.
  4. Mixed Signedness (Fallback): Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the signed integer operand.
Type Resolution Visualization The following valid C11 code demonstrates how the compiler resolves the common type during binary operations based on the conversion hierarchy. It utilizes _Generic and _Static_assert to prove the resulting types at compile-time, including preprocessor conditionals to handle architecture-dependent integer resolutions:
#include <limits.h>

#define ASSERT_TYPE(expr, type) \
    _Static_assert(_Generic((expr), type: 1, default: 0), "Type mismatch")

void demonstrate_conversions(void) {
    double d = 1.0;
    float f = 1.0f;
    short s = 1;
    char c = 1;
    unsigned char uc = 1;
    int i = 1;
    unsigned int ui = 1U;
    long l = 1L;
    unsigned long ul = 1UL;
    long long ll = 1LL;

    /* Phase 1: Floating-Point Dominance (No integer promotions applied) */
    ASSERT_TYPE(d + i, double);
    ASSERT_TYPE(f + ll, float);

    /* Phase 2: Integer Promotions (Applied because no floats are present) */
    ASSERT_TYPE(s + s, int);
    ASSERT_TYPE(c + uc, int);

    /* Phase 3: Integer Resolution */
    
    /* Same Signedness: Rank Promotion */
    ASSERT_TYPE(ui + ul, unsigned long);
    ASSERT_TYPE(i + ll, long long);

    /* Mixed Signedness: Unsigned Rank >= Signed Rank */
    ASSERT_TYPE(i + ui, unsigned int);
    ASSERT_TYPE(l + ul, unsigned long);

    /* Mixed Signedness: Signed Rank > Unsigned Rank */
#if LONG_MAX > UINT_MAX
    /* Signed type can represent all values of the unsigned type (e.g., LP64) */
    ASSERT_TYPE(l + ui, long);
#else
    /* Signed type cannot represent all values; fallback to unsigned corresponding type (e.g., ILP32, LLP64) */
    ASSERT_TYPE(l + ui, unsigned long);
#endif
}
Master C with Deep Grasping Methodology!Learn More