2

I caught myself checking if the difference between two unsigned numbers was >= 0. I ran a test running Visual Studio 2022 Preview with the following code. In both cases the answer was true. That seems right to me as how could an unsigned number be considered negative?

However, when I changed all the types from UINT32 to UINT16 or UINT8, the first comparison returned false. I suppose it is related to the native size. But shouldn't the result be the same regardless of size? (UINT64 seems to behave like UINT32.)

#include <Windows.h>
#include <iostream>
using namespace std;

int main()
{
  UINT32 a = 5;
  UINT32 b = 10;
  UINT32 c = 0;

  if ((a - b) > 0)
  {
    cout << "\nTrue.";
  }
  else
  {
    cout << "\nFalse";
  }

  c = a - b;

  if ((c) > 0)
  {
    cout << "\nTrue.";
  }
  else
  {
    cout << "\nFalse";
  }
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
MaryK
  • 71
  • 6
  • Would be interesting to know if the second comparison also fails if you enable optimizations. – PMF Nov 07 '21 at 12:12
  • Initially the Basic Runtime Checks was set to both and I had to change it to default in order to change the optimization away from disabled. After changing runtime checks to default the result was always true and true for both sizes regardless of the optimization choice. The odd thing was that when I changed the runtime checks back to both the result was still true and true for both sizes. Restarting VS gave me the original results. – MaryK Nov 07 '21 at 17:55

1 Answers1

0

The issue arises because, when a and b are UINT16 or UINT8 types, they have ranks less than that of the int type, so, by the "usual arithmetic conversion" rules, they are promoted to int before the a - b operation is performed, and the result of that operation is also of int type.

From this draft C++17 Standard (bolding for emphasis is mine):

7.6 Integral promotions     [conv.prom]

1    A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (6.7.4) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

However, on your platform, the UINT32 type has a rank that is the same as that of int; so, in that case, no promotion is performed, and the result of a - b is a UINT32 (which cannot be negative).


If you have the relevant feature enabled (it is by default, IIRC), then the Visual Studio IDE will actually tell you what the issue is, if you declare an auto local variable and initialize it with a - b. The following shows the popup displayed, when hovering over the d variable, for the case when using the UINT32 type:

enter image description here

However, when we change the type to UINT16, we see that the a - b expression is, indeed, evaluated as an int:

enter image description here

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • Must types be promoted for comparisons? – MaryK Nov 07 '21 at 23:53
  • It's not in the comparison where the promotion happens but in the `a - b` *subtraction* operation. The operands are promoted to `int` and - more improtantly - the *result* is an `int`. In your second case, where you then assign the result to `c`, the type is converted back to the (smaller) unsigned type. – Adrian Mole Nov 08 '21 at 00:12