On x86_64 CentOS 7 GCC 4.8.5 C++11:
#include <iostream>
int main()
{
std::cout << ((ssize_t)1 - (size_t)5) << '\n';
}
// Output: 18446744073709551612
But:
#include <iostream>
int main()
{
std::cout << ((ssize_t)1 - (unsigned int)5) << '\n';
}
// Output: -4
And on i686 CentOS 6 GCC 4.8.2 C++11, they both give 4294967292
so I have to do this:
#include <iostream>
int main()
{
std::cout << ((ssize_t)1 - (ssize_t)5) << '\n';
}
// Output: -4
An extremely contrived example, obviously, and I understand that I'm hitting various clauses in the integral promotion rules depending on the platform/implementation-defined type equivalences, but on a Thursday my brain can't unravel them for a rigourous assessment.
What exactly is the sequence of standard rules that leads me to these results?
Disclaimer: I refer to paragraph 11 of clause 5 of the latest draft N4606 of C++17. The wording I quote and cite is contained in paragraph 9 of N3337, which is virtually identical to the C++11 standard, and in that form also in the FD of C++14, so this answer applies to these standards as well.
Assuming that ssize_t
and size_t
have equal rank, in your first case, [expr]/(11.5.5) applies:
Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
1 will be converted to the unsigned version of ssize_t
, which should be size_t
—hence the unsigned underflow, and the value of 2sizeof(size_t)*8
-4.
For your second case, assuming that the rank of unsigned
is less than that of ssize_t
, and the latter can hold all of the former's values; see [expr]/(11.5.4):
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.
I.e. 5
will be converted to ssize_t
, and so we get the negative result. If ssize_t
is not of greater rank than unsigned
, we'd get 2sizeof(unsigned)*8
-4; if instead ssize_t
could not hold all of unsigned
's values, we get the negative result again, because we fall through to the aforementioned (11.5.5).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With