#include <iostream>
#define TRY_INT
void testRun()
{
#ifdef TRY_INT //test with unsigned
unsigned int value1{1}; //define some unsigned variables
unsigned int value2{1};
unsigned int value3{2};
#else //test with fixed width
uint16_t value1{1}; //define fixed width unsigned variables
uint16_t value2{1};
uint16_t value3{2};
#endif
if ( value1 > value2 - value3 )
{
std::cout << value1 << " is bigger than: " << value2 - value3 << "\n";
}
else
{
std::cout << value1 << " is smaller than: " << value2 - value3 << "\n";
}
}
int main()
{
testRun();
return 0;
}
with unsigned integers I get:
1 is smaller than: 4294967295
with fixed width unsigned int, output is:
1 is smaller than: -1
My expectation was it would wrap around as well, does this have something to do with std::cout?
I guess it is caused by integral promotion. Citing form cppreference:
...arithmetic operators do not accept types smaller than
int
as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion, if applicable.
unsigned char
,char8_t
(since C++20) orunsigned short
can be converted toint
if it can hold its entire value range...
Consequently, if uint16_t
is just an alias for unsigned short
on your implementation, value2 - value3
is calculated with int
type and the result is also int
, that's why -1
is shown.
With unsigned int
, no promotion is applied and the whole calculation is performed in this type.
In the latest online C++ Draft, see [conv.prom/1]:
A prvalue of an integer type other than
bool
,char16_t
,char32_t
, orwchar_t
whose integer conversion rank is less than the rank ofint
can be converted to a prvalue of typeint
ifint
can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of typeunsigned int
.