0
int main(){
 int64_t a = -1;
 uint32_t b = -1;

 bool c = a > b;
 std:: cout << c << std::endl;
 
 return 0;
}

My understanding is b which is a smaller type will be converted to the bigger type of a (unit32 to int64):

Comparing int with long and others

Then a which is a signed value will be turned to an unsigned value:

Signed/unsigned comparisons

Essentially our comparison will be turned into:

18446744073709551615 > 4294967295

But my c result is false. What am I missing here?

Dan
  • 2,694
  • 1
  • 6
  • 19
  • 1
    Essentially the comparison will be turned into `-1 > 4294967295`. – Eljay Jun 01 '21 at 20:32
  • but looking at `a` as an unsigned number isn't `-1`. its `18446744073709551615`, isn't a signed value supposed to turn into unsigned if the other value is also unsigned? – Dan Jun 01 '21 at 20:34
  • `b` is not `18446744073709551615` (that's way too big to fit into a 32-bit unsigned int), it's `4294967295`. – Eljay Jun 01 '21 at 20:35
  • @Eljay `a` is that value not `b`. – Dan Jun 01 '21 at 20:36
  • Have you tried this in [cppinsights](https://cppinsights.io/s/a5cb9a52) to see what happens? – MatG Jun 01 '21 at 20:39
  • The value of `a` is -1. The value of `b` is 4294967295. The common type will be `std::int64_t` so your comparison between two `std::int64_t` comparing `-1 > 4294967295 ` which is `false`. You may be assuming the common type will be unsigned, but that is not accurate because `int64_t` can fully represent the range of values represented by `uint32_t`. – François Andrieux Jun 01 '21 at 20:53
  • 1
    [Promotion rules](https://en.cppreference.com/w/cpp/language/implicit_conversion). – Eljay Jun 01 '21 at 21:14

1 Answers1

5

Given int64_t a and uint32_t b, in a > b, b will be zero-extended to 64 bits (remember, it's unsigned, so it's really 4294967295 and not -1), and then a comparison is performed. The relevant comparison is that -1 > 4294967295 is false.

Relevant bits of the C++ standard are under "6.8.4 Integer conversion rank [conv.rank]", "The rank of a signed integer type shall be greater than the rank of any signed integer type with a smaller width." and "The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.", under "7.4 Usual arithmetic conversions [expr.arith.conv]", "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." and under "7.6.9 Relational operators [expr.rel]", "The usual arithmetic conversions (7.4) are performed on operands of arithmetic or enumeration type."

  • But the second link above says `When comparing signed with unsigned, the compiler converts the signed value to unsigned`, isn't `a` supposed become unsigned? – Dan Jun 01 '21 at 20:37
  • 1
    @Dan That was in reference to an `int` and an `unsigned int`. You have a `long` and an `unsigned int`. This part of the answer applies to you instead: "Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent all the values of an unsigned int, the unsigned int shall be converted to a long int; otherwise both operands shall be converted to unsigned long int." – Joseph Sible-Reinstate Monica Jun 01 '21 at 20:38
  • @AlexReynolds The expression `-1L > 0U` is false. If `a` became unsigned, wouldn't that be true instead? – Joseph Sible-Reinstate Monica Jun 01 '21 at 20:46
  • @JosephSible-ReinstateMonica That comparison is `false` if `sizeof(long) > sizeof(unsigned)`. This distinction is bypassed by the question because it uses fixed width integers instead. – François Andrieux Jun 01 '21 at 20:56
  • @FrançoisAndrieux Good point; I was indeed assuming the AMD64 SysV ABI. – Joseph Sible-Reinstate Monica Jun 01 '21 at 20:57