The standard library vector::size()
gives size_t
an unsigned number. At one of the CppCon talks, I heard that someone (is it Chandler Carrut?) Said that it was unsuccessful and that he should rather use signed integers.
The background is that overflow is not defined for signed integers, so the compiler has a lot more freedom. In a conversation, Carrut showed how an index uint8_t
as an index for
in bzip2 creates a lot more x86 machine instructions than int8_t
because it must explicitly simulate overflow using masks and shifts.
The code I'm working on now has certain sizes that are strictly positive. They are represented as size_t
. It seems worthy because it shows that they cannot be negative. On the other hand, there is no need for a specific modular arithmetic, so if the signed integer is large enough (we go around 200), an unsigned integer will have the wrong interface for the arithmetic we require.
At some point in the code, there are loops from 0 to this size. And then the loop indices are subtracted and the absolute value is accepted.
When I compiled it with my more modern GCC 7, it wasn’t able to allow the correct overload std::abs
, because it size_t - size_t
seems to give ambiguous values. I changed the code to use int
in loop indices:
for (int t1 = 0; t1 < Lt; t1++) {
for (int t2 = 0; t2 < Lt; t2++) {
Now abs(t1 - t2)
works fine. But the comparison t1 < Lt
gives a warning, because it is a comparison between signed and unsigned numbers.
What is the right approach?
- Use unsigned integers for a non-negative value, and then use
static_cast<int>()
whenever I need to do the substitution. - Use signed integers for loop indices, but unsigned integers for container sizes. Then use
static_cast<int>
in comparison. - . ,
static_cast<int>
, .