CType Conversion & Casting

Type Conversion & Casting

C frequently needs to convert a value from one type to another — sometimes automatically, sometimes because you explicitly asked for it. Understanding when each kind of conversion happens, and what it can silently cost you, prevents a large class of subtle numeric bugs.

Implicit conversion (usual arithmetic conversions)

When an expression mixes different numeric types, C automatically converts the operands to a common type before performing the operation, following a set of rules known as the usual arithmetic conversions. In general, the "narrower" or "lower-ranked" type is converted up to match the "wider" one — for example, if an int and a double appear in the same expression, the int is converted to double before the operation happens.

C
#include <stdio.h>

int main(void) {
    int whole = 3;
    double fraction = 0.5;

    double result = whole + fraction;  /* whole is converted to double first */
    printf("%.1f\n", result);
    return 0;
}
3.5
Explicit casting

You can force a conversion yourself using the cast syntax, (type)expression. This is useful when you want to be explicit about an intended conversion, or when you need to override the default arithmetic conversion rules.

C
#include <stdio.h>

int main(void) {
    double pi = 3.14159;
    int truncated = (int)pi;         /* explicit cast to int */

    printf("truncated: %d\n", truncated);
    return 0;
}
truncated: 3
Narrowing conversions lose data
Casting double to int truncates — it does not round
Converting a floating-point value to an integer type discards the fractional part entirely; it does not round to the nearest whole number. `(int)3.99` produces `3`, not `4`, and `(int)-3.99` produces `-3`, not `-4` — the fractional part is simply cut off toward zero. If you actually want rounding, use `round()` from `<math.h>` before casting.

C
#include <stdio.h>
#include <math.h>

int main(void) {
    printf("(int)3.99  = %d\n", (int)3.99);   /* 3, not 4 */
    printf("(int)-3.99 = %d\n", (int)-3.99);  /* -3, not -4 */

    printf("rounded: %d\n", (int)round(3.99)); /* 4, with explicit rounding */
    return 0;
}
(int)3.99  = 3
(int)-3.99 = -3
rounded: 4
Integer promotion, briefly

Before most arithmetic or comparison operations, small integer types — char, short, and _Bool — are automatically promoted to int (or unsigned int, if int cannot represent all their values). This is why arithmetic on two char values, as seen on the char-type page, actually happens as int arithmetic behind the scenes, and why the result of a comparison between chars is technically an int.

A subtle bug: integer division before conversion

A very common mistake is performing integer division and only converting to a floating-point type afterward — by then, the fractional part is already gone. The order of operations matters.

C
#include <stdio.h>

int main(void) {
    int a = 5, b = 2;

    double wrong = a / b;           /* integer division happens FIRST: 5/2 = 2 */
    double right = (double)a / b;   /* a is converted to double BEFORE dividing */

    printf("wrong: %.1f\n", wrong);
    printf("right: %.1f\n", right);
    return 0;
}
wrong: 2.0
right: 2.5

In the wrong line, both operands of / are int, so C performs integer division — 5 / 2 evaluates to 2 — and only afterward converts that already-truncated 2 into 2.0 for storage in the double. Casting one operand to double before the division, as in the right line, forces the entire division to happen in floating-point.

Conversion

When it happens

Data loss risk

Implicit (usual arithmetic conversions)

Automatically, in mixed-type expressions

Usually safe (widening)

Explicit cast, widening (e.g. int → double)

You write (double)x

None

Explicit cast, narrowing (e.g. double → int)

You write (int)x

Fractional part discarded

Integer division

Both operands are integer types

Fractional result truncated before any later conversion

  • Mixed-type expressions are implicitly converted to a common, usually wider, type before the operation runs.

  • Explicit casts use (type)expression and let you force a conversion.

  • Casting a floating-point value to an integer type truncates toward zero — it never rounds.

  • Small integer types are promoted to int before most operations (integer promotion).

  • Cast operands to a floating-point type before dividing if you need a fractional result — casting after the division is too late.