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.

Implicit conversion, or type coercion, is the automatic transformation of one data type into another by the C compiler during expression evaluation, assignment, or function calls, without the use of an explicit cast operator. The compiler performs these conversions based on a strict set of predefined rules to ensure operand compatibility.

Integer Promotion

Before certain operations are performed—specifically unary arithmetic operators (+, -, ~), shift operators (<<, >>), and as part of the usual arithmetic conversions for binary operators—C applies integer promotion. Data types with an integer conversion rank lower than int (such as char and short, both signed and unsigned) are automatically promoted to int. If an int cannot represent all values of the original type, the value is promoted to unsigned int. Logical operators (&&, ||, !) do not trigger integer promotions. Instead, they evaluate their operands as scalar types and compare them directly against zero.
char a = 10;
char b = 20;

// 'a' and 'b' are implicitly promoted to 'int' before the addition occurs.
// The result is an 'int', which is then assigned to 'c'.
int c = a + b; 

Usual Arithmetic Conversions

When an operation involves operands of different types, the compiler applies the “usual arithmetic conversions” to establish a common type. Floating-Point and Mixed Types: If either operand is a floating-point type, the compiler converts the other operand to the floating-point type with the highest precision among the two. Crucially, if one operand is a floating-point type and the other is an integer type, the integer operand is implicitly converted to the floating-point type. The hierarchy is:
  1. If either operand is long double, the other is converted to long double.
  2. Otherwise, if either operand is double, the other is converted to double.
  3. Otherwise, if either operand is float, the other is converted to float.
Integer Types: If neither operand is a floating-point type, integer promotions are applied to both operands. Then, the compiler determines the common type based on the integer conversion rank and representable range:
  1. If both operands have the same signedness, the operand with the lower rank is converted to the type of the operand with the higher rank.
  2. If the unsigned operand has a rank greater than or equal to the rank of the signed operand, the signed operand is converted to the unsigned operand’s type.
  3. If the signed operand’s type can represent all values of the unsigned operand’s type, the unsigned operand is converted to the signed operand’s type.
  4. Otherwise, both operands are converted to the unsigned type corresponding to the type of the signed operand.
int i = 10;
double d = 5.5;

// Mixed-type operation: 'i' (int) is implicitly converted to 'double'.
// The resulting expression evaluates to a 'double'.
d + i; 

long l = 500L;
unsigned int u = 100U;

// The resulting type of (l + u) depends on the architecture's data model:
// - If sizeof(long) > sizeof(unsigned int), 'u' converts to 'long' (Rule 3).
// - If sizeof(long) == sizeof(unsigned int), both convert to 'unsigned long' (Rule 4).
l + u; 

Boolean Conversions

The _Bool type (accessible as bool via <stdbool.h>) follows unique implicit conversion rules. When any scalar value (integer, floating-point, or pointer) is converted to _Bool, the result is 0 if the value compares equal to zero, and 1 if the value is non-zero. This is a strict boolean evaluation, not a truncation.
#include <stdbool.h>
#include <stddef.h>

// Evaluates to 1 (true). Floating-point 0.5 is non-zero.
bool b1 = 0.5;  

// Evaluates to 1 (true). The value is not truncated to 0 via modulo arithmetic.
bool b2 = 256;  

// Evaluates to 0 (false). NULL compares equal to zero.
bool b3 = NULL; 

Pointer Conversions

Implicit conversions also apply to pointer types in specific contexts, which is fundamental to C memory management and array handling:
  • Array-to-Pointer Decay: An expression of type “array of T” is implicitly converted to a “pointer to T” that points to the initial element of the array. This decay occurs in almost all contexts, except when the array is the operand of sizeof, _Alignof, or the address-of operator (&), or when it is a string literal used to initialize an array.
  • void * Conversion: A pointer to void (void *) serves as a generic pointer. It can be implicitly converted to or from a pointer to any other object type or incomplete type without requiring an explicit cast.
#include <stdlib.h>

int arr[5] = {1, 2, 3, 4, 5};

// Array-to-pointer decay: 'arr' implicitly converts from 'int[5]' to 'int *' 
// pointing to &arr[0].
int *ptr = arr; 

// void * conversion: malloc returns 'void *', which is implicitly 
// converted to 'int *' during assignment.
int *dynamic_ptr = malloc(sizeof(int) * 5);

Assignment Conversion

During an assignment operation, the expression on the right-hand side (RHS) is implicitly converted to the data type of the variable on the left-hand side (LHS).
  • Promotion: If the LHS is a larger integer type, the RHS value is extended (zero-extended for unsigned, sign-extended for signed).
  • Demotion (Truncation): If the LHS is a smaller integer type (excluding _Bool), the RHS integer value is truncated to fit the target type.
  • Integer to Integer (Out-of-Range): Assigning an out-of-range integer value to a signed integer type results in implementation-defined behavior. Assigning an out-of-range integer value to an unsigned integer type guarantees modulo wrap-around based on the maximum representable value of the unsigned type.
  • Floating-Point to Integer: When a floating-point value is converted to an integer type (other than _Bool), the fractional part is discarded (truncated towards zero). If the resulting integral part cannot be represented by the target integer type (whether signed or unsigned), the behavior is strictly Undefined Behavior.
// Promotion: int (42) is converted to double (42.0)
double d = 42; 

// Demotion: double (3.99) is truncated to int (3). Fractional part is lost.
int i = 3.99; 

// Integer modulo wrap-around: int (257) exceeds unsigned char capacity (typically 255). 
// The value wraps around via modulo arithmetic (257 % 256 = 1).
unsigned char c = 257; 

// Undefined Behavior: The floating-point value exceeds the maximum representable 
// value of an unsigned int. This does NOT guarantee modulo wrap-around.
unsigned int u = 1e20; 

Function Call and Return Conversions

Implicit conversion occurs at function boundaries and behaves differently depending on whether a function prototype is visible to the compiler. With a Visible Prototype:
  • Arguments: Arguments passed to a function are implicitly converted to the types of the corresponding parameters, following standard assignment conversion rules.
  • Return Values: The expression provided in a return statement is implicitly converted to the function’s declared return type.
Default Argument Promotions: If a function has no visible prototype, or if an argument corresponds to the variable-argument portion of a variadic function (such as printf), the compiler applies default argument promotions:
  • Integer types smaller than int undergo standard integer promotion.
  • Arguments of type float are implicitly promoted to double.
#include <stdio.h>

double process_value(double input) {
    int status_code = 1;
    
    // Return conversion: 'status_code' (int) is implicitly converted to 'double' (1.0) 
    // to match the declared return type of the function.
    return status_code; 
}

int main(void) {
    // Argument conversion: '5' (int) is implicitly converted to 'double' (5.0) 
    // to match the parameter type of 'process_value'.
    double result = process_value(5); 
    
    float f = 3.14f;
    char c = 'A';
    
    // Variadic function call: 
    // 'f' undergoes default argument promotion to 'double'.
    // 'c' undergoes integer promotion to 'int'.
    printf("%f %c\n", f, c);
    
    return 0;
}
Master C with Deep Grasping Methodology!Learn More