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