Skip to content
  • Integer Promotion & Type Conversions · C

Integer Promotion & Type Conversions

LearnViaNotes @learnvianotes· 3 min read

Before most arithmetic, C silently converts operands: small integers are promoted to int, and mixed types are brought to a common type. Signed/unsigned mixing is the classic source of bugs.

Integer promotion

Any char, short or bit-field (signed or unsigned) used in an expression is first converted to int (or unsigned int if int can’t hold all its values).

C
#include <stdio.h>

int main(void) {
    unsigned char a = 200, b = 100;
    int sum = a + b;                 /* promoted to int: 300, no wrap */
    unsigned char stored = a + b;    /* converted back: 300 mod 256 */
    printf("%d %d\n", sum, stored);

    char c = 'x';
    printf("%zu %zu\n", sizeof c, sizeof(c + 0));   /* char vs int */

    unsigned char ones = 0xFF;
    printf("%d\n", ~ones);           /* ~ applied to int 255 → -256, not 0 */
    return 0;
}
Output
300 44
1 4
-256

The usual arithmetic conversions

  1. Any floating operand?

    Convert the other to the widest floating type involved (long double > double > float).

  2. Otherwise promote

    Apply integer promotion to both operands.

  3. Same signedness

    Convert to the higher-rank type (int < long < long long).

  4. Mixed signedness

    If the unsigned type has rank ≥ the signed one, the signed operand becomes unsigned. Otherwise, if the signed type can represent every unsigned value, convert to the signed type; else to its unsigned counterpart.

C
#include <stdio.h>

int main(void) {
    int neg = -1;
    unsigned int one = 1;
    /* -1 is converted to unsigned: 4294967295 > 1 */
    if ((unsigned)neg > one) printf("-1 > 1u as unsigned!\n");
    printf("%u\n", (unsigned)neg);

    long long big = -1;
    printf("%d\n", big < one);     /* long long can hold every unsigned int: stays signed */
    return 0;
}
Output
-1 > 1u as unsigned!
4294967295
1

Clang warns about the implicit version of this comparison (-Wsign-compare, part of -Wextra) — one more reason to keep warnings on:

C — signed/unsigned comparison (rejected by -Wextra -Werror)
#include <stdio.h>
#include <string.h>

int main(void) {
    int i = -1;
    if (i < strlen("abc"))       /* int vs size_t: i becomes huge */
        printf("smaller\n");
    return 0;
}

Explicit casts and narrowing

C
#include <stdio.h>

int main(void) {
    double d = 3.99;
    int truncated = (int)d;          /* toward zero, not rounded */
    int negative = (int)-3.99;
    printf("%d %d\n", truncated, negative);

    int total = 7, count = 2;
    printf("%d %.1f\n", total / count, (double)total / count);

    int big = 300;
    unsigned char small = (unsigned char)big;   /* modulo 256 */
    signed char sc = (signed char)200;          /* implementation-defined */
    printf("%d %d\n", small, sc);
    return 0;
}
Output
3 -3
3 3.5
44 -56
ConversionResult
Any integer → unsigned typeWell defined: value modulo 2ᴺ
Out-of-range integer → signed typeImplementation-defined (wraps on all real compilers; C23 mandates two’s complement)
Floating → integerTruncates toward zero; UB if the value doesn’t fit
Integer → floatingMay lose precision for large values
double → floatRounded; UB/inf if out of range

Why does (unsigned char)255 + 1 give 256 and not 0?

What is the result of -1 < 0u?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report