This page describes the rules for arithmetic conversions that the compiler adheres to when the language specified is extended. Described are:
Usual Unary Conversions
The usual unary conversions reduce the types of values that the
compiler must handle. The compiler uses the usual unary conversions on:
The following table lists the types of values that the usual unary conversions affect:
Type of Value... before Conversion after Conversion char int unsigned char unsigned int short int unsigned short unsigned int float double array of type pointer to type
Note: The compiler performs the usual unary conversion of float to double on arguments in function calls only. When a float object appears as an operand of !, -, ~, *, <, or >, the compiler does not perform a usual unary conversion.
Explicit Conversions describes how the compiler performs conversions.
Usual Arithmetic Conversions
The usual arithmetic conversions reduce the types of objects that
the compiler handles when performing arithmetic operations. Many compilers perform
arithmetic operations only on objects having one of several data types. These types are: int,
unsigned int, long, unsigned long, float,
double, and long double. If all operands do not have one
of these types, the system converts the values of the operands according to the following
procedures:
The following sections describe the usual arithmetic conversion procedures.
Widening
Widening expands the size of a value (for example, short
to int by padding bits located to the left of the value with a copy of
the sign bit). Widening does not affect the sign of the value.
The following table shows the types of values that the compiler widens:
Type of Value... before Widening after Widening char int OR unsigned int unsigned char unsigned int short int unsigned short unsigned int float double
The compiler treats char objects as unsigned values. Widening of a char yields an int that has a positive value.
Many compilers widen float values to double values before performing arithmetic operations. Where possible, the compiler performs double-precision arithmetic on float values.
Type Balancing
Type balancing makes all operands have the same data type. If both
of the operands do not have the same size data type, the compiler converts the value of
the operand having the smaller type to a value having the larger type. For example, if the
operand count has type int and the operand maximum has
type long, the compiler converts the value of count to type long.
Type balancing does not affect the sign of the value.
Sign Balancing
Sign balancing makes both operands have the same data type
(signed or unsigned). If one operand has an unsigned
type, the compiler converts the other operand to that unsigned type.
Otherwise, both operands remain signed.
Assignment Conversion
An assignment conversion makes the value of the right operand have
the same data type as the left operand. Only the following assignment type combinations
are supported by the language:
Type of... Left Operand Right Operand Any arithmetic type Any arithmetic type Pointer to type Pointer to type, or,
the NULL pointerStructure of type Structure of type Union of type Union of type
Explicit Conversions describes how the compiler performs conversions from one arithmetic type to another arithmetic type.
Explicit Conversions
When the compiler converts the values of one data type to the
value of another data type, the compiler usually performs one of the following
conversions:
Reduction conversions | Change the data type of a value to a smaller size data type (for example, a value having type double to a value having type float). |
Expansion conversions | Change the data type of a value to a larger size data type (for example, a value having type float to a value having type double). |
Pointer conversions | Change the data type to which a pointer refers or change an integral type to a pointer. |
void conversions | Discard the value of a function call. |
volatile conversions | Give a nonvolatile data object the volatile attribute. |
The following sections describe these conversions.
Integral Reduction | The compiler converts an integral value to a narrower type (for example, a long to a short); the compiler truncates the value by discarding the most significant bits. |
double or long double to float | The compiler converts a double-precision floating-point value (long double or double) to a single-precision floating-point value (float); the compiler rounds off the double-precision value. |
Floating-Point to Integral | The language does not define the method of converting floating-point values to integral values. The compiler drops the fraction part of the floating-point value. |
Integral to Floating-Point | The C language does not prohibit integral sizes from having a higher precision than the floating-point sizes. If a higher precision integer is converted to a float, the resulting float might experience a loss of precision. |
Floating-Point Expansion | Although many compilers perform all floating-point arithmetic in double precision only, the C compiler extended language level performs double-precision arithmetic when all operands have type float. When on operand has type float and another operand has type double or long double, the compiler converts the float to the equivalent double or long double value. |
Integral to Floating-Point | The compiler converts narrower integral values to equivalent floating-point values. |
Unsigned Arithmetic Expansion | The compiler converts narrower unsigned arithmetic values to wider unsigned arithmetic values by padding the values with zeros. |
Signed Arithmetic Expansion | The language does not define how narrower signed arithmetic values are converted to wider signed arithmetic values. When a narrower arithmetic value is converted to a wider signed arithmetic value, the compiler pads bits located to the left of the value with a copy of the sign bit. |
Pointer to Pointer | When two pointers to objects of the same type are subtracted, the compiler performs the operation on the values of the pointers and divides the result by the length of the objects to which the pointers refer. The result is an integer that indicates the distance between the specified objects in the array. For example, if p points to the second element in an array and q points to the fifth element in the array, the expression p - q yields -3. |
Integral to Pointer | When an integral value is subtracted from a pointer, the compiler multiplies the integral value by the length of the object to which the pointer refers to produce an address offset, which can be added or subtracted from the pointer value. The result is a pointer (having the same type as the original pointer) that refers to an object assumed to be in the same array. |
void Conversions
A program cannot use or apply conversions to the (nonexistent)
value of a void object. To convert the result of a function call to type void,
use the cast operator. Such a conversion discards the value of a function call used in an
expression statement. For example, the following statement discards the result of the
function call add():
(void)add();
volatile to Nonvolatile | Through an explicit cast, you can assign the address of a volatile data object to a pointer that is defined as pointing to a nonvolatile data object. If the volatile object is referenced through such a pointer, the result is undefined. |
Nonvolatile to volatile | You can assign the address of a nonvolatile data object that is defined as pointing to a volatile data object. If the nonvolatile object is referenced through such a pointer, the compiler treats the nonvolatile object as a volatile object. |
Arithmetic Conversions
Conflicts Between extended C and Other Levels
Extensions to RT C Provided by extended C
Exceptions to ansi C Addressed by classic
C
saal2 C Deviations from SAA Level 2 C
Summary of C Language Level Conflicts