Implicit type conversion rules in C++ operators
Asked Answered
B

9

217

I want to be better about knowing when I should cast. What are the implicit type conversion rules in C++ when adding, multiplying, etc. For example,

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

et cetera...

Will the expression always be evaluated as the more precise type? Do the rules differ for Java? Please correct me if I have worded this question inaccurately.

Bugg answered 6/4, 2011 at 7:44 Comment(2)
Keep in mind ^ is XOR.Rumba
@int ^ float = compile error :)Disprove
A
281

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>
Ape answered 6/4, 2011 at 7:56 Comment(23)
"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?Indoxyl
More precisely: built-in operators always act on the same types. User defined-operators can mix arbitrary types, so long as at least one operand is of a user-defined type.Deliberative
@Rafal: Yes. int is supposed to be the most efficient integer type for operation on a particular platform. char must always be 1 but short can be the same size as int.Ape
@Rafał: yes, it is very strange and it is is in the standard. In a lot of cases, the architecture you describe could use its super-efficient char type. If the value of char + char is assigned to a char, then it can just do the arithmetic in char and for example wrap around. But if the result is assigned to int then it has to do the arithmetic in a type large enough to get the correct result when it's more than CHAR_MAX.Inofficious
@Martin: on the architecture Rafał describes, though, supposing the most efficient integer type is 8 bits then of course that can't be chosen as int. If we read the standard as requiring that all other integer types be no faster than int, then the compiler would have to avoid optimizations that use char arithmetic where it works, to slow things down. I'm pretty sure that's not the intention of the standard, it's just vague advice to implementers that if all else is equal, pick a fast type for int.Inofficious
In practice, on a hypothetical architecture where registers are 64bit and 64bit arithmetic is faster than 32bit, I wouldn't be at all surprised if an implementation completely ignored the advice and kept int at 32 bits. You could then have an argument whether "natural size suggested by the architecture of the execution environment" in the standard is a sufficiently well-defined concept for that to be non-conforming behavior. I'd say that what architectures "suggest" is subjective enough that it doesn't bar that, it just means int (unlike long) won't gratuitously be 37 bits.Inofficious
What does C99 have to do with it? This question is about C++. Say "C++0x only".Gomel
@ Tomalak Geret'kal: You have enough rep to edit the question. But its technically not part of C++ though every compiler (apart from one) the I have used provides this extension (usually its just a nice take from there C compiler). And I did not mention C++0x becuase (a) I forgot and (b) its not yet official (but mostly because I forgot).Ape
If either is long and the other is unsigned int, both of them will be promoted to unsigned long (same for long long).Adlee
@Calmarius: The version of the standard with the wording was n2009 published on 2006-04-21. The wording changed in n2134 published in 2006-11-03. So you are a bit out of date. But there is a grain of truth in what you say assuming that signed type has a larger rank than the unsigned type AND can not represent all values of the unsigned type. Exact wording can be found in n3376 Section 5 Expr Paragraph 9.Ape
I just want to emphasize the fact that int gets promoted to unsigned int!!! I've struggled with bugs for days because I was under the impression that both would be promoted to int or long so that a possible negative result would not cause an underflow/wrap-around.Unsuccessful
Example of the problem "int gets promoted to unsigned int": ((int) 4) - ((unsigned int) 5) will result in 4294967295 for 32 bit ints and 32 bit unsigned ints.Unsuccessful
@stop-forgetting-my-accounts: Updates incorporated.Ape
@LokiAstari: why there is no promotion from int to long int in C++? Why this program ideone.com/7VHdoU fails in compilation?Soundboard
@PravasiMeet: That is a completely different question then is asked here. Also the error messages generated are very clear on why it failed call of overloaded 'fun(int)' is ambiguous. Maybe you should create a question that ask why it is ambiguous. PS. Remove all the deleted functions and it will work.Ape
The answer is different than what the C++11 spec now says. Consider when unsigned and long (both 32-bit), this answers says long, yet C++11 says unsigned long.Atp
Many thanks for this listing. However, you need to work on your coding style (regarding compulsive alignment ;->). That's not readable -- I have to horizontally scroll. For example, you don't really need two identical columns.Preponderance
Great answer! Here is an answer I wrote elsewhere which contains a full C++ program you can use to test expressions to see what the return type is, and if it has been implicitly cast by to the compiler to something you don't intend: https://mcmap.net/q/128351/-c-casting-to-byte-unit8_t-during-subtraction-won-39-t-force-underflow-like-i-expect-output-is-int16_t-whyDeannedeans
@MartinYork what about type conversion when comparing int > float or float > int or short > int or int > short? do you have a stackoverflow.com link?Yanirayank
What about between float and double?Desireah
@AaronFranke Those are covered above.Ape
The table names an order in which the conversion happens? Meaning, the conversion higher in table overrules the one lower in table?Dicker
@Dicker Yes. But it is an obvious order. You are always converting one operand to a larger type to prevent information loss.Ape
D
42

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 ]

Dietary answered 6/4, 2011 at 7:49 Comment(5)
...so long as the other type is neither double nor long double.Chilon
@Charles: Correct. I quoted the relevant section from the Standard to clarify further.Dietary
So can an integer always be converted to float without any data loss? (e.g. by zero-ing the exponent and using everything for the mantissa) ?Ampersand
This answer is out-of-date. Suggest update. In particular, long long and unsigned long not addressed right here.Atp
@MarcoA. a 32-bit float doesn't have enough bits in the mantissa (24 bits for IEEE-754) for a 32-bit int, so there might be some data loss. A 64-bit double should be just fine.Blackford
E
20

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.

Enlist answered 26/5, 2014 at 15:36 Comment(1)
These rules were the same in all versions of C++, except for scoped enumerations which were added in C++11 of courseUball
E
8

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.

Eridanus answered 20/1, 2012 at 1:24 Comment(0)
B
5

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

Brutish answered 6/4, 2011 at 8:8 Comment(2)
Stroustrup can recommend what he likes, but using a sign-able int for a number that never needs to be negative is a complete waste of a full 50% of the available range. I'm certainly no Stroustrup, but I use unsigned by default and signed only when I have a reason.Discommon
That's all well and good, underscore_d, until the day when you have to subtract. The primary problem with unsigned numbers in C++ is that when you perform subtraction, they stay unsigned. So suppose you write a function to see if a std::vector is in order. You might write bool in_order(vector<T> vec) { for ( int i = 0; i < size() - 1; ++i) { if (vec[i + 1] < vec[i]) return false; } return true; and then you'd be annoyed to find that it crashes for empty vectors because size() - 1 returns 18446744073709551615.Indole
S
3

My solution to the problem got WA(wrong answer), then i changed one of int to long long int and it gave AC(accept). Previously, I was trying to do long long int += int * int, and after I rectify it to long long int += long long int * int. Googling I came up with,

1. Arithmetic Conversions

Conditions for Type Conversion:

Conditions Met ---> Conversion

  • Either operand is of type long double. ---> Other operand is converted to type long double.

  • Preceding condition not met and either operand is of type double. ---> Other operand is converted to type double.

  • Preceding conditions not met and either operand is of type float. ---> Other operand is converted to type float.

  • Preceding conditions not met (none of the operands are of floating types). ---> Integral promotions are performed on the operands as follows:

    • If either operand is of type unsigned long, the other operand is converted to type unsigned long.
    • If preceding condition not met, and if either operand is of type long and the other of type unsigned int, both operands are converted to type unsigned long.
    • If the preceding two conditions are not met, and if either operand is of type long, t he other operand is converted to type long.
    • If the preceding three conditions are not met, and if either operand is of type unsigned int, the other operand is converted to type unsigned int.
    • If none of the preceding conditions are met, both operands are converted to type int.

2 . Integer conversion rules

  • Integer Promotions:

Integer types smaller than int are promoted when an operation is performed on them. If all values of the original type can be represented as an int, the value of the smaller type is converted to an int; otherwise, it is converted to an unsigned int. Integer promotions are applied as part of the usual arithmetic conversions to certain argument expressions; operands of the unary +, -, and ~ operators; and operands of the shift operators.

  • Integer Conversion Rank:

    • No two signed integer types shall have the same rank, even if they have the same representation.
    • The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision.
    • The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.
    • The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any.
    • The rank of any standard integer type shall be greater than the rank of any extended integer type with the same width.
    • The rank of char shall equal the rank of signed char and unsigned char.
    • The rank of any extended signed integer type relative to another extended signed integer type with the same precision is implementation-defined but still subject to the other rules for determining the integer conversion rank.
    • For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 has greater rank than T3.
  • Usual Arithmetic Conversions:

    • If both operands have the same type, no further conversion is needed.
    • If both operands are of the same integer type (signed or unsigned), the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
    • 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 is converted to the type of the operand with unsigned integer type.
    • 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 is converted to the type of the operand with signed integer type.
    • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type. Specific operations can add to or modify the semantics of the usual arithmetic operations.
Stupor answered 15/6, 2014 at 3:1 Comment(0)
P
1

The type of the expression, when not both parts are of the same type, will be converted to the biggest of both. The problem here is to understand which one is bigger than the other (it does not have anything to do with size in bytes).

In expressions in which a real number and an integer number are involved, the integer will be promoted to real number. For example, in int + float, the type of the expression is float.

The other difference are related to the capability of the type. For example, an expression involving an int and a long int will result of type long int.

Poisson answered 6/4, 2011 at 7:50 Comment(3)
This is not true. On may platforms a long is "bigger" than a float but what is the type of long + float?Chilon
-1: What do you mean by biggest ? Is a float bigger than an int ? Or vice versa ?Crematorium
Thank you for your comments. Yep the size in bytes here is of no interest at all. As it comes out, obviously putting biggest in italics is not enough to explain the answer. Anyway, it does not make sense to explain it more deeply, since now there are other, very thorough answers.Poisson
B
1

Whole chapter 4 talks about conversions, but I think you should be mostly interested in these :

4.5 Integral promotions [conv.prom]
An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type; other-
wise, the source rvalue can be converted to an rvalue of type unsigned int.
An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2) can be converted to an rvalue of the first
of the following types that can represent all the values of its underlying type: int, unsigned int,
long, or unsigned long.
An rvalue for an integral bit-field (9.6) can be converted to an rvalue of type int if int can represent all
the values of the bit-field; otherwise, it can be converted to unsigned int if unsigned int can rep-
resent all the values of the bit-field. If the bit-field is larger yet, no integral promotion applies to it. If the
bit-field has an enumerated type, it is treated as any other value of that type for promotion purposes.
An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true
becoming one.
These conversions are called integral promotions.

4.6 Floating point promotion [conv.fpprom]
An rvalue of type float can be converted to an rvalue of type double. The value is unchanged.
This conversion is called floating point promotion.

Therefore, all conversions involving float - the result is float.

Only the one involving both int - the result is int : int / int = int

Bucella answered 6/4, 2011 at 7:53 Comment(0)
V
-3

Caveat!

The conversions occur from left to right.

Try this:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0
Vortex answered 4/8, 2014 at 6:44 Comment(1)
That's not because of the conversion but because of operator precedence. j + i * k would result in 101.Statue

© 2022 - 2024 — McMap. All rights reserved.