Discussion: Aristotle’s Sum of Parts
Executed code to understand the output and gain insights into type promotion and usual arithmetic conversions.
Run the code
Now, it’s time to execute the code and observe the output.
#include <iostream>#include <type_traits>int main(){char char1 = 1;char char2 = 2;// True if the type of char1 + char2 is charstd::cout << std::is_same_v<decltype(char1 + char2), char>;}
Understanding the output
This is supposed to be a fun course, but sometimes, we need to talk about sad topics like this.
As we’ve figured out by now, the type of char + char
is unfortunately not char
. So what is it, then?
Binary operations in C++
For many binary operations, such as +
, -
, *
, /
, >
, ==
, ^
, and more, the operands must be of the same type. We don’t have to ensure that ourselves, though; C++ will take care of it. C++ is, in fact, very eager to implicitly convert between types when we’re not looking, and this is one of the more confusing cases. Meet the usual arithmetic conversions.
Usual arithmetic conversions
The usual arithmetic conversions are performed on the operands to these operators to ensure both operands are of the same type. This common type is also the type of the result. For instance, if we add a float
and an int
, the int
is first converted to a float
, and the result is a float
. If we add a float
and a double
, the float
is first converted to a double
, and the result is a double
. It makes sense so far.
Confusion with integer types
The confusion starts when both operands are of integer types, especially if they are of the same type. For instance, if we add a char
and an int
, the char
is first converted to an int
, and the result is an int
. It still makes sense. But what if we add a char
and a short
? Rather than converting the char
to a short
, both operands are converted to an int
. And it gets worse: if we add two char
types, which are already of the same type, they’re still converted to a different type!
Integral promotions
Let’s see what the usual arithmetic conversions do to our char1 + char2
expression. Since both operands are of integer types, a process known as integral promotions is performed on both of them. The idea is to convert smaller integer types to int
or unsigned int
before performing the arithmetic expression. After converting both operands, we can now add them using regular int
or unsigned int
addition and get an int
or unsigned int
as a result.
The rule for promoting a smaller integer type is that it can be converted to an int
if int
can represent all the values of the smaller type; otherwise, it can be converted to an unsigned int
. Does a char
fit in an int
? Usually, it does, but that depends on the implementation.
Implementation-defined behavior
A complicating factor here is that the sizes of fundamental types in C++ are not fixed. An implementation can decide that int
is 16 bits or 64 bits, and even that char
and long
are of the same size. The only rules are these:
Each of
signed char
,short
,int
,long
, andlong long
is at least as large as the preceding type in the list.For each of the types in that list, an
unsigned
version exists, which has the same size as thesigned
version.
Some minimum sizes are also defined:
Type | Minimum Width (Bits) |
| 8 |
| 16 |
| 16 |
| 32 |
| 64 |
On a typical 64-bit Linux, Windows, or macOS system, int
is 32 bits, whereas long
is 64 bits on Linux/macOS and 32 bits on Windows. But a conforming implementation could equally well decide that all integer types are 64 bits.
Special case of char
In this puzzle, we’re interested in char
in particular, but char
is curiously missing in the discussion above. What’s going on? The char
is a bit special in that the implementation can choose whether to back it by signed char
or unsigned char
. In either case, char
is a distinct type. So char
, signed char
, and unsigned char
are actually three different types, and whether or not a plain char
is signed is implementation-defined!
Remember, we’re interested in whether all the values in char
fit in an int
to figure out whether our char
types would be converted to int
or unsigned int
. Normally, they all fit, so both operands of char1 + char2
would be converted to int
, and the result would also be an int
.
But let’s say that the implementation has chosen char
and int
to both be 16 bits. Let’s also say that the implementation has chosen that char
is unsigned. The range of int
is then char
types don’t fit in an int
! On these systems, the operands of char1 + char2
would instead be promoted to unsigned int
, and the result would also be an unsigned int
.
So, the type of char1 + char2
can either be int
or unsigned int
. All we know for sure is that it’s not char
.
Level up your interview prep. Join Educative to access 70+ hands-on prep courses.