Reputation: 1221
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.
However, I wonder what happens when the compiler has to convert a to an unsigned value and creates a temporary object of unsigned type, what happens after? The expression should now be 10 - 4294967254
.
Upvotes: 38
Views: 19527
Reputation: 234875
signed
type a
is converted to an unsigned
type prior to subtraction. That conversion happens according to [conv.integral] p3:Otherwise, the result is the unique value of the destination type that is congruent to the source integer modulo 2N, where N is the width of the destination type.
Algebraically a
becomes be a very large positive number, and certainly larger than u
.
u - a
is an nameless temporary object and will be of unsigned
type. (You can verify this by writing auto t = u - a
and inspecting the type of t
in your debugger.) Mathematically, this will first be a negative number, but after 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 optimize out all these conversions.
Upvotes: 10
Reputation: 41
Here is the disassemble code which says: first sets -42
to its complement and do the sub operation. So the result is 10 + 42
0x0000000000400835 <+8>: movl $0xa,-0xc(%rbp)
0x000000000040083c <+15>: movl $0xffffffd6,-0x8(%rbp)
0x0000000000400843 <+22>: mov -0x8(%rbp),%eax
0x0000000000400846 <+25>: mov -0xc(%rbp),%edx
0x0000000000400849 <+28>: sub %eax,%edx
0x000000000040084b <+30>: mov %edx,%eax`
Upvotes: -3
Reputation: 320747
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
.
Upvotes: 49