Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit type conversion rules in C++ operators

People also ask

What is implicit type conversion in C?

Implicit Type Conversion is also known as 'automatic type conversion'. It is done by the compiler on its own, without any external trigger from the user. It generally takes place when in an expression more than one data type is present.

Does C have implicit conversion?

Implicit type conversion in C language is the conversion of one data type into another datatype by the compiler during the execution of the program. It is also called automatic type conversion.

What is implicit type conversion with example?

In implicit typecasting, the conversion involves a smaller data type to the larger type size. For example, the byte datatype implicitly typecast into short, char, int, long, float, and double. The process of converting the lower data type to that of a higher data type is referred to as Widening.

Which operator is used for type conversion?

Cast operator: () A type cast provides a method for explicit conversion of the type of an object in a specific situation.


In C++ operators (for POD types) always act on objects of the same type.
Thus if they are not the same one will be promoted to match the other.
The type of the result of the operation is the same as operands (after conversion).

if:
either is      long double       other is promoted >      long double
either is           double       other is promoted >           double
either is           float        other is promoted >           float
either is long long unsigned int other is promoted > long long unsigned int
either is long long          int other is promoted > long long          int
either is long      unsigned int other is promoted > long      unsigned int
either is long               int other is promoted > long               int
either is           unsigned int other is promoted >           unsigned int
either is                    int other is promoted >                    int

Otherwise:
both operands are promoted to int

Note. The minimum size of operations is int. So short/char are promoted to int before the operation is done.

In all your expressions the int is promoted to a float before the operation is performed. The result of the operation is a float.

int + float =>  float + float = float
int * float =>  float * float = float
float * int =>  float * float = float
int / float =>  float / float = float
float / int =>  float / float = float
int / int                     = int
int ^ float =>  <compiler error>

Arithmetic operations involving float results in float.

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

For more detail answer. Look at what the section §5/9 from the C++ Standard says

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result.

This pattern is called the usual arithmetic conversions, which are defined as follows:

— If either operand is of type long double, the other shall be converted to long double.

— Otherwise, if either operand is double, the other shall be converted to double.

— Otherwise, if either operand is float, the other shall be converted to float.

— Otherwise, the integral promotions (4.5) shall be performed on both operands.54)

— Then, if either operand is unsigned long the other shall be converted to unsigned long.

— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent all the values of an unsigned int, the unsigned int shall be converted to a long int; otherwise both operands shall be converted to unsigned long int.

— Otherwise, if either operand is long, the other shall be converted to long.

— Otherwise, if either operand is unsigned, the other shall be converted to unsigned.

[Note: otherwise, the only remaining case is that both operands are int ]


Since the other answers don't talk about the rules in C++11 here's one. From C++11 standard (draft n3337) §5/9 (emphasized the difference):

This pattern is called the usual arithmetic conversions, which are defined as follows:

— If either operand is of scoped enumeration type, no conversions are performed; if the other operand does not have the same type, the expression is ill-formed.

— If either operand is of type long double, the other shall be converted to long double.

— Otherwise, if either operand is double, the other shall be converted to double.

— Otherwise, if either operand is float, the other shall be converted to float.

— Otherwise, the integral promotions shall be performed on both operands. Then the following rules shall be applied to the promoted operands:

— If both operands have the same type, no further conversion is needed.

— Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank shall be converted to the type of the operand with greater rank.

— Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.

— Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.

— Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

See here for a list that's frequently updated.


This answer is directed in large part at a comment made by @RafałDowgird:

"The minimum size of operations is int." - This would be very strange (what about architectures that efficiently support char/short operations?) Is this really in the C++ spec?

Keep in mind that the C++ standard has the all-important "as-if" rule. See section 1.8: Program Execution:

3) This provision is sometimes called the "as-if" rule, because an implementation is free to disregard any requirement of the Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program.

The compiler cannot set an int to be 8 bits in size, even if it were the fastest, since the standard mandates a 16-bit minimum int.

Therefore, in the case of a theoretical computer with super-fast 8-bit operations, the implicit promotion to int for arithmetic could matter. However, for many operations, you cannot tell if the compiler actually did the operations in the precision of an int and then converted to a char to store in your variable, or if the operations were done in char all along.

For example, consider unsigned char = unsigned char + unsigned char + unsigned char, where addition would overflow (let's assume a value of 200 for each). If you promoted to int, you would get 600, which would then be implicitly down cast into an unsigned char, which would wrap modulo 256, thus giving a final result of 88. If you did no such promotions,you'd have to wrap between the first two additions, which would reduce the problem from 200 + 200 + 200 to 144 + 200, which is 344, which reduces to 88. In other words, the program does not know the difference, so the compiler is free to ignore the mandate to perform intermediate operations in int if the operands have a lower ranking than int.

This is true in general of addition, subtraction, and multiplication. It is not true in general for division or modulus.


If you exclude the unsigned types, there is an ordered hierarchy: signed char, short, int, long, long long, float, double, long double. First, anything coming before int in the above will be converted to int. Then, in a binary operation, the lower ranked type will be converted to the higher, and the results will be the type of the higher. (You'll note that, from the hierarchy, anytime a floating point and an integral type are involved, the integral type will be converted to the floating point type.)

Unsigned complicates things a bit: it perturbs the ranking, and parts of the ranking become implementation defined. Because of this, it's best to not mix signed and unsigned in the same expression. (Most C++ experts seem to avoid unsigned unless bitwise operations are involved. That is, at least, what Stroustrup recommends.)