Previous Table of Contents Next


3.3.10. Default Conversions

C has a simple but general set of rules for performing automatic conversions when values of different types participate in an expression, or when a value of one type is assigned to a variable of a different type. In an assignment, automatic conversions are performed if the types are both numeric, or if they are certain assignment-compatible types of pointers. In a mixed-mode arithmetic operation expression, the general rule is that most operators always operate on two values of the same type, such that when values of dissimilar types meet across a binary operator, one or both are promoted to a common type before the operation takes place. The promotion is to the largest of the floating-point types involved if either operand is floating-point, or to long if either operand is long, and/or to unsigned if either operand is unsigned.

There is a certain bias in the language towards types int and double. (Some of this bias is historical and is gradually being removed.) Many compilers perform all floating-point arithmetic in type double, and the math-related library functions (see section 3.10.5) all use type double. All arithmetic always takes place using at least type int; types char and short int are always promoted to int before being operated on.

The promotion of unsigned values can be tricky: When a seemingly smaller unsigned type is promoted to a larger type, the exact promotion depends on the actual sizes of the types involved, which is machine dependent. The goal is to preserve the value being promoted. For example, if an unsigned short value is being promoted to int, and if type int is in fact bigger than type short int, then the promotion is to int, but if the two types are the same size, the promotion is to unsigned int. This rule, though it sounds reasonable enough as stated here, can lead to surprises, so care must be taken when writing expressions that involve mixtures of small and large, signed and unsigned operands.

As a simple example of the default promotion rules, given the declarations

int i;
long int li;
float f;
double d;

the expression i + li causes i to be promoted to long int, the expression i + f causes i to be promoted to float, and the expression li + d causes li to be promoted to double. The assignment d = i causes an implicit conversion of i’s value to double, and the assignment i = d causes an implicit conversion of d’s value to int.

Conversions from smaller integral types to larger are, of course, always exact. If the types are signed, sign extension occurs so that the value is preserved. (Sign extension occasionally causes surprising results if the value being manipulated is not being thought of as an integer value, but rather as a bit pattern.) Conversions from integral types to floating point are usually exact, except perhaps if a very large long int value cannot be represented with full precision in the floating-point type.

Conversions from floating point to integer always involve simple truncation of the fractional part, as long as the whole number part can be represented by the destination integer. (The result is otherwise undefined; note too that truncation of a value such as 3.99999 yields a result very different than rounding would.) A conversion of a larger integer to a smaller one is undefined if the smaller integer is signed and cannot represent the value. If the smaller integer is unsigned, however, the conversion is performed modulo the range of the unsigned destination. (That is, on a machine with 16-bit short ints, the assignment in

unsigned short int us;
long int li = 123456;
us = li;

is equivalent to

us = li % 65536;

and yields 57,920.)

These rules produce reasonable, expected results in most circumstances. Care must be taken in a few situations, however. First of all, the destination or context of an expression is never considered when deciding how the expression should be evaluated; the evaluation is always determined strictly by the two operands of each operator. In the code

int i = 1000, j = 2000;
long int li;
li = i * j;                         /*WRONG*/

the multiplication is carried out using ints, and may overflow, even though the destination is a long int. In the code

int i = 15, j = 4;
float f;
f = i / j;                /* WRONG, if 3.75 is wanted */

an integer division is performed, resulting in the value 3, even though the destination is a float. Explicitly typed constants or explicit conversion operators (as described in the next section) can be used to achieve the desired result in these situations.


Previous Table of Contents Next