Arithmetic Conversions for extended Level C

This page describes the rules for arithmetic conversions that the compiler adheres to when the language specified is extended. Described are:

  • Usual Unary Conversions
  • Usual Arithmetic Conversions
  • Widening
  • Type Balancing
  • Sign Balancing
  • Assignment Conversion
  • Explicit Conversions
  • Reduction Conversions
  • Expansion Conversions
  • Pointer Conversions
  • void Conversions
  • volatile Conversions

  • 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:

    1. Widening values that do not have data types appropriate for arithmetic operations.
    2. Type balancing values in operations that have more than one operand.
    3. Sign balancing values in operations that have more than one operand.

    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 pointer
    Structure 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.

    Reduction 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.

    Expansion Conversions

    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 Conversions

    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 Conversions

    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.

     



    Language Levels


    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