Type Conversion
The logger's daily total is 644 tenths from 3 readings, so the average should be about 214.67. The code stores it in a double, yet it prints 214.0. Nothing is broken; C did exactly what its conversion rules say, one step at a time. Learn the steps and this bug becomes impossible to miss.
The rule
Mixed arithmetic climbs to the wider type; assignment squeezes back down.
Before an operator works, both operands are brought to a common type (the usual arithmetic conversions):
- Small integer types (
char,short,bool) are first promoted toint. - If either operand is floating-point, the other is converted to that floating type (
long doublebeatsdoublebeatsfloat). - Otherwise the smaller integer type is converted to the larger one. If a signed and an unsigned type of the same size meet, the signed value becomes unsigned.
Assignment converts the result to the target's type:
doubleto an integer type truncates toward zero:(int)21.9is 21 and(int)-3.8is -3. If the value does not fit in the integer type, the behaviour is undefined.- A value converted to an unsigned type wraps modulo its range.
- An out-of-range value converted to a smaller signed type gives an implementation-defined result.
A cast, (type)value, forces a conversion exactly where you put it:
int total = 644;
int count = 3;
double wrong = total / count; /* int / int = 214, then 214.0 */
double right = (double)total / count; /* double / int: count climbs too, 214.666... */The order is the whole point. In wrong, the division finishes as integer division before the assignment converts anything, and the fraction is already gone. Writing (double)(total / count) fails the same way: the parentheses make the integer division happen first, and the cast only converts its result.
The signed/unsigned rule causes a classic trap:
int t = -5;
unsigned int limit = 10;
if (t < limit) { /* never runs: -5 becomes 4294967291 with 32-bit unsigned */ }-Wextra warns about this with -Wsign-compare.
The shortcut
Before each operator, name the two types. Promote, find the common type, compute, then convert once more at the =.
First operator: 7 / 2
Both are
int, so integer division: 3. The half is dropped here.
Drills
Answer fast — trust the rule.
What does double r = 7 / 2; store?
What is the value of (double)7 / 2?
What does int n = (int)-3.8; store?
With 32-bit unsigned int, what is the value of -1 < 1u?
What does int big = (int)1e20; store on a platform with 32-bit int?
Remember
- Mixed arithmetic climbs to the wider type; assignment squeezes back down.
- Shortcut: name the two types before each operator, and cast before the division, not after.
- Trap: signed meets unsigned and the signed value turns into a huge unsigned one.
