what happens when i mix signed and unsigned types ?

I'm studying the C++ language and i have some doubt about type conversion, could you explain me what happens in an expression like this :

unsigned int u = 10; 
int a = -42; 
std::cout << u - a << std::endl;

Here i know that the result will be 52 if i apply the rules when we have two mathematical operators.But i wonder what happens when the compiler to convert a to an unsigned value creates a temporary of unsigned type, what happens after ? The expression now should be 10 -4294967254.


Solution 1:

In simple terms, if you mix types of the same rank (in the sequence of int, long int, long long int), the unsigned type "wins" and the calculations are performed within that unsigned type. The result is of the same unsigned type.

If you mix types of different rank, the higher-ranked type "wins", if it can represent all values of lower-ranked type. The calculations are performed within that type. The result is of that type.

Finally, if the higher-ranked type cannot represent all values of lower-ranked type, then the unsigned version of the higher ranked type is used. The result is of that type.

In your case you mixed types of the same rank (int and unsigned int), which means that the whole expression is evaluated within unsigned int type. The expression, as you correctly stated, is now 10 - 4294967254 (for 32 bit int). Unsigned types obey the rules of modulo arithmetic with 2^32 (4294967296) as the modulo. If you carefully calculate the result (which can be expressed arithmetically as 10 - 4294967254 + 4294967296), it will turn out as the expected 52.

Solution 2:

1) Due to standard promotion rules, the signed type a is promoted to an unsigned type prior to subtraction. That promotion happens according to this rule (C++ standard 4.7/2):

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type).

Algebraically a becomes be a very large positive number and certainly larger than u.

2) u - a is an anonymous temporary and will be a unsigned type. (You can verify this by writing auto t = u - a and inspecting the type of t in your debugger.) Mathematically this will be a negative number but on implicit conversion to the unsigned type, a wraparound rule similar to above is invoked.

In short, the two conversion operations have equal and opposite effects and the result will be 52. In practice, the compiler might optimise out all these conversions.