Assignment Conversions

In assignment operations, the type of the value being assigned is converted to the type of the variable that receives the assignment. C allows conversions by assignment between integral and floating types, even if information is lost in the conversion. The conversion method used depends on the types involved in the assignment, as described in “Usual Arithmetic Conversion” and in the following sections.

Type qualifiers do not affect the allowability of the conversion although a const l-value cannot be used on the left side of the assignment.

Conversions from Signed Integral Types

When a signed integer is converted to an unsigned integer with equal or greater size and the value of the signed integer is not negative, the value is unchanged. The conversion is made by sign-extending the signed integer. A signed integer is converted to a shorter signed integer by truncating the high-order bits. The result is interpreted as an unsigned value, as shown in this example.

int i = -3;

unsigned u;

u = i;

printf( "%u\n", u ); /* Prints 65533 on 16-bit computers */

No information is lost when a signed integer is converted to a floating value, except that some precision may be lost when a long int or unsigned long int value is converted to a float value.

Table 4.2 summarizes conversions from signed integral types. This table assumes that the char type is signed by default. If you use a compile-time option to change the default for the char type to unsigned, the conversions given in Table 4.3 for the unsigned char type apply instead of the conversions in Table 4.2.

Table 4.2 Conversions from Signed Integral Types

From To Method

char1 short Sign-extend
char long Sign-extend
char unsigned char Preserve pattern; high-order bit loses function as sign bit
char unsigned short Sign-extend to short; convert short to unsigned short
char unsigned long Sign-extend to long; convert long to unsigned long
char float Sign-extend to long; convert long to float
char double Sign-extend to long; convert long to double
char long double Sign-extend to long; convert long to double
short char Preserve low-order byte
short long Sign-extend
short unsigned char Preserve low-order byte
short unsigned short Preserve bit pattern; high-order bit loses function as sign bit
short unsigned long Sign-extend to long; convert long to unsigned long
short float Sign-extend to long; convert long to float
short double Sign-extend to long; convert long to double
short long double Sign-extend to long; convert long to double
long char Preserve low-order byte
long short Preserve low-order word
long unsigned char Preserve low-order byte
long unsigned short Preserve low-order word
long unsigned long Preserve bit pattern; high-order bit loses function as sign bit
long float Represent as float. If long cannot be represented exactly, some precision is lost.
  ,  

Table 4.2 Conversions from Signed Integral Types (continued)

From To Method

long double Represent as double. If long cannot be represented exactly as a double, some precision is lost.
long long double Represent as double. If long cannot be represented exactly as a double, some precision is lost.

1 All char entries assume that the char type is signed by default.

The int type is equivalent to either the short type or the long type, depending on the implementation. Conversion of an int value proceeds the same as for a short or a long, whichever is appropriate. For the Microsoft C compiler, an integer is the same as a short for 16-bit targets, and is equivalent to a long for 32-bit targets.

Conversions from Unsigned Integral Types

An unsigned integer is converted to a shorter unsigned or signed integer by truncating the high-order bits, or to a longer unsigned or signed integer by zero-extending.

When the value with integral type is demoted to a signed integer with smaller size, or an unsigned integer is converted to its corresponding signed integer, the value is unchanged if it can be represented in the new type. However, the value it represents changes if the sign bit is set. The results in the following example are true for 16-bit computers.

int j;

unsigned k = 65533;

j = k;

printf( "%d\n", j ); /* Prints -3 */

If it cannot be represented, the result is implementation-defined. See “Type-Cast Conversions” for information on the Microsoft C compiler's handling of demotion of integers. The same behavior results from integer conversion or from type casting the integer.

Unsigned values are converted in a way that preserves their value and is not representable directly in C. The only exception is a conversion from unsigned long to float which loses at most the low-order bits. Otherwise value is preserved, signed or unsigned. When a value of integral type is converted to floating, and the value is outside the range representable, the result is undefined. (See “Storage of Basic Types” for information about the range for integral and floating-point types.)

Table 4.3 summarizes conversions from unsigned integral types.

Table 4.3 Conversions from Unsigned Integral Types

From To Method

unsigned char char Preserve bit pattern; high-order bit becomes sign bit
unsigned char short Zero-extend
unsigned char long Zero-extend
unsigned char unsigned short Zero-extend
unsigned char unsigned long Zero-extend
unsigned char float Convert to long; convert long to float
unsigned char double Convert to long; convert long to double
unsigned char long double Convert to long; convert long to double
unsigned short char Preserve low-order byte
unsigned short short Preserve bit pattern; high-order bit becomes sign bit
unsigned short long Zero-extend
unsigned short unsigned char Preserve low-order byte
unsigned short unsigned long Zero-extend
unsigned short float Convert to long; convert long to float
unsigned short double Convert to long; convert long to double
unsigned short long double Convert to long; convert long to double
unsigned long char Preserve low-order byte
unsigned long short Preserve low-order word
unsigned long long Preserve bit pattern; high-order bit becomes sign bit
unsigned long unsigned char Preserve low-order byte
unsigned long unsigned short Preserve low-order word
unsigned long float Convert to long; convert long to float
unsigned long double Convert directly to double
unsigned long long double Convert to long; convert long to double

The unsigned int type is equivalent either to the unsigned short type or to the
unsigned long
type, depending on the target environment. Conversion of an
unsigned int
value proceeds in the same way as conversion of an unsigned short or an unsigned long, whichever is appropriate. For the Microsoft C compiler, an integer is the same as a short for 16-bit targets and is equivalent to a long for 32-bit targets. Conversions from unsigned long values to float are not accurate if the value being converted is larger than the maximum positive signed long value.

Conversions from Floating-Point Types

A float value converted to a double or long double, or a double converted to a long double, undergoes no change in value. A double value converted to a float value is represented exactly, if possible. Precision may be lost if the value cannot be represented exactly. If the result is out of range, the behavior is undefined. See “Floating-Point Constants” for the range of floating-point types.

A floating value is converted to an integral value by first converting to a long, then from the long value to the specific integral value, as described below in Table 4.4. The decimal portion of the floating value is discarded in the conversion to a long. If the result is still too large to fit into a long, the result of the conversion is undefined.

Microsoft Specific

When converting a doubleor long doublefloating-point number to a smaller floating-point number, the value of the floating-point variable is truncated toward zero when an underflow occurs. An overflow causes a run-time error.¨Table 4.4 summarizes conversions from floating types.

Table 4.4 Conversions from Floating-Point Types

From To Method

float char Convert to long; convert long to char
float short Convert to long; convert long to short
float long Truncate at decimal point. If result is too large to be represented as long, result is undefined.
float unsigned short Convert to long; convert long to unsigned short
float unsigned long Convert to long; convert long to unsigned long
float double Change internal representation
float long double Change internal representation
double char Convert to float; convert float to char
double short Convert to float; convert float to short
double long Truncate at decimal point. If result is too large to be represented as long, result is undefined.
double unsigned short Convert to long; convert long to unsigned short
double unsigned long Convert to long; convert long to unsigned long
double float Represent as a float. If double value cannot be represented exactly as float, loss of precision occurs. If value is too large to be represented as float, the result is undefined.
long double char Convert to float; convert float to char
  ,  

Table 4.4 Conversions from Floating-Point Types (continued)

From To Method

long double short Convert to float; convert float to short
long double long Truncate at decimal point. If result is too large to be represented as long, result is undefined.
long double unsigned short Convert to long; convert long to unsigned short
long double unsigned long Convert to long; convert long to unsigned long
long double float Represent as a float. If double value cannot be represented exactly as float, loss of precision occurs. If value is too large to be represented as float, the result is undefined.
long double double The long double value is treated as double.

Note:

Conversions from float, double, or long double values to unsigned long are not accurate if the value being converted is larger than the maximum positive long value.

Conversions to and from Pointer Types

A pointer to one type of value can be converted to a pointer to a different type. However, the result may be undefined because of the alignment requirements and sizes of different types in storage. A pointer to an object may be converted to a pointer to an object whose type requires less or equally strict storage alignment, and back again without change.

A pointer to void may be converted to or from a pointer to any type, without restriction or loss of information. If the result is converted back to the original type, the original pointer is recovered.

If a pointer is converted to another pointer with the same type but having different or additional qualifiers, the new pointer is the same as the old except for restrictions imposed by the new qualifier.

A pointer value can also be converted to an integral value. The conversion path depends on the size of the pointer and the size of the integral type, according to the following rules:

If the size of the pointer is greater than or equal to the size of the integral type, the pointer behaves like an unsigned value in the conversion, except that it cannot be converted to a floating value.

If the pointer is smaller than the integral type, the pointer is first converted to a pointer with the same size as the integral type, then converted to the integral type.

Conversely, an integral type can be converted to a pointer type according to the following rules:

If the integral type is the same size as the pointer type, the conversion simply causes the integral value to be treated as a pointer (an unsigned integer).

If the size of the integral type is different from the size of the pointer type, the integral type is first converted to the size of the pointer, using the conversion paths given in Tables 4.2 and 4.3. It is then treated as a pointer value.

An integral constant expression with value 0 or such an expression cast to type void * may be converted by a type cast, by assignment, or by comparison to a pointer of any type. This produces a null pointer that is equal to another null pointer of the same type, but this null pointer is not equal to any pointer to a function or to an object. Integers other than the constant 0 may be converted to pointer type, but the result is not portable.

See “Special Keywords in Declarators” for information about conversions on pointers made with the __near, __far, and __huge keywords.

Conversions from Other Types

Since an enum value is an int value by definition, conversions to and from an enum value are the same as those for the int type. An int is equivalent to either a short or a long, depending on the target environment.

Microsoft Specific

For the Microsoft C compiler, an integer is the same as a shortfor 16-bit targets and is equivalent to a longfor 32-bit targets. No conversions between structure or union types are allowed.

Any value may be converted to type void, but the result of such a conversion can be used only in a context where an expression value is discarded, such as in an expression statement.

The void type has no value, by definition. Therefore, it cannot be converted to any other type, and other types cannot be converted to void by assignment. However, you can explicitly cast a value to void type, as discussed in the next section.¨