0

Having such simple code:

DWORD i = 0xFFFFFFF5; // == 4294967285(signed) ==  -11(unsigned)

    if((unsigned)i == -11)
      OutputDebugString(L"equal");
    else
      OutputDebugString(L"not equal");

The condition is meet - i'm getting "equal" output.

My question is WHY is that happen since in the condition we have f(4294967285 == -11) considering the explicit unsigned cast on the left side of the operator? Why is the cast ignored?

t.niese
  • 39,256
  • 9
  • 74
  • 101
darro911
  • 136
  • 6
  • 2
    Cast isn't ignored. `-11` is implicitly casted to `unsigned` due to [promotion rules](https://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_promotions). I had a nice duplicate for that somewhere... – Yksisarvinen Jun 08 '22 at 17:33
  • You forced an unsigned comparison. So why should it be false if they differ only in sign? – David Schwartz Jun 08 '22 at 17:34
  • `DWORD` is already unsigned. The cast is unnecessary. – Retired Ninja Jun 08 '22 at 17:35
  • @Yksisarvinen. ok but when i change it to `if ((unsigned)iii == (signed)-11)` is STILL returns true("equal")...!? –  darro911 Jun 08 '22 at 17:36
  • `(unsigned)iii == (signed)-11)` compares an `unsigned` value to a `signed` value. `signed` is a synonym for `signed int` and `int`. So it compares an `unsigned` to an `int`. The rules for converting operands are applied, and the `int` is converted to `unsigned`. There is no way in C++ to compare two numbers of different types with the built-in operators. Two operands to `==` are always converted to a common type. – Eric Postpischil Jun 08 '22 at 17:41
  • 1
    @Yksisarvinen -- right, except that it's implicitly **converted**. There is no such thing as an implicit cast. A cast is something you write in your source code to tell the compiler to do a conversion. So it's always explicit. – Pete Becker Jun 08 '22 at 17:41
  • @darro911 `-11` is already considered an `int` (=`signed`) without the cast. The compiler recognizes that you're applying the operator `==` to operands of type `unsigned` and `signed` resulting in it requiring to convert the `signed` parameter to `unsigned` according to the standard, i.e. it becomes `if (iii == static_cast((signed) -11))` or equivalent `if (iii == static_cast(-11))`. If you want to compare signed ints, you need to do `if(static_cast(iii) == -11)` – fabian Jun 08 '22 at 17:41
  • You can't compare `unsigned int` and `signed int`. Compiler will always perform promotions to get them to the same type (in this case `unsigned int`), you can't disable that. – Yksisarvinen Jun 08 '22 at 17:42
  • @Yksisarvinen So in `(unsigned)iii == (signed)-11)` the `(signed)` cast in the left side of `-11` is just ignored? –  darro911 Jun 08 '22 at 17:45
  • @darro911 Yes, -11 is signed already, so casting it to signed has no effect. – john Jun 08 '22 at 17:57
  • @Yksisarvinen Ok so to sum it up - even if the -11 is SIGNED it is automatically and forcefully converted to unsigned(4294967285) and there is NO way to tell the compiler to treat is as signed as it was written in the condition? –  darro911 Jun 08 '22 at 18:04
  • I think you still don't understand that it is not possible to compare `unsigned int` and `int`. They are different types, it's like comparing apples to oranges. They *must* be converted to one and the same type before comparison happens. If you try to compare `unsigned int` and `int`, compiler will always perform promotion before comparing. If you want `4294967285` and `-11` to be unequal, you need to either cast at least one operand to a bigger type (e.g. `(long long)iii == -11`) or find another comparison method (e.g. converting to string representations or converting to floats or something) – Yksisarvinen Jun 08 '22 at 18:11
  • @Yksisarvinen Ok, friend I DO understand that it is not possible to compare unsigned int and int. All i said is there is no way to force the compiler to do some counter conversion - convert the `4294967285` to signed (-11) and then compare -11 to -11 instead of converting -11 to unsigned `4294967285` and then comparing `4294967285` to `4294967285` what is indeed being done? –  darro911 Jun 08 '22 at 18:55
  • You can, if you cast `iii` to `int`. – Yksisarvinen Jun 08 '22 at 20:03
  • @Yksisarvinen So You mean that in case of `if ((int)i == -11)` the compiler'll convert `i` to `signed int`: `- 11` and then make a comparison like `-11 ==-11`? –  darro911 Jun 09 '22 at 09:32

1 Answers1

1

DWORD is unsigned or equivalent, a 32-bit unsigned integer in your C++ implementation. DWORD i = 0xFFFFFFF5; initializes i to FFFFFFF516 = 4,294,967,285.

In (unsigned)i == -11, i is converted to unsigned, which yields the same value, 4,294,967,285. The other operand, -11, has type int and value −11.

When two numbers are compared with ==, they are converted to be some common type. The rules for operating on an unsigned and an int result in the int being converted to unsigned. When −11 is converted to unsigned in a C++ implementation in which unsigned is 32 bits, the result of the conversion is 232−11 = 4,294,967,296 − 11 = 4,294,967,285.

Then the two unsigned values are compared. Since they are both 4,294,967,285, the comparison indicates they are equal.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312