1

I have found in my c++ program that assert() calls abort() in a case similiar to the following code snippet:

int a = -1;
unsigned int b = 5;

assert(a < b);

As a human I can tell that -1 is definitely smaller than 5, regardless of the fact that one is an int and the other an unsigned int. Why can't the compiler?

I have already found the solution, which is that this assert is just nonsensical since an unsigned will always be positive (I had kind of forgotten that the variable in my actual code was an unsigned), but I am just curious as to why this happens.

Timangar
  • 32
  • 6
  • 2
    Your compiler should have warned you about comparing variables of different signed"ness". Did it? When comparing variables best always cast the values to the same signed or unsigned. Do mind that this may truncate values. – Bart Aug 14 '21 at 11:06
  • 2
    Well the human is wrong here. You're comparing unsigned and signed here which means the result is converted to an **unsigned** integral type and since the conversion of `-1` to unsigned yields the largest possible value, you're applying the first parameter of the comparison is greater after this conversion. Your compiler very likely warns you about this issue btw. – fabian Aug 14 '21 at 11:07
  • When comparing an `int` with an `unsigned`, the `int` is converted to `unsigned` first, and then the converted value is compared. Converting `-1` to `unsigned` gives the maximum value an `unsigned` can represent - which is greater than `5`. – Peter Aug 14 '21 at 11:07
  • The a variable is casted to a (very large) unsigned int before the comparison is executed – Viktor Sehr Aug 14 '21 at 11:07
  • 3
    Try [`assert(std::cmp_less(a, b));`](https://en.cppreference.com/w/cpp/utility/intcmp) – Ted Lyngmo Aug 14 '21 at 11:08
  • @Enlico Indeed. I didn't know about it myself a week ago. – Ted Lyngmo Aug 14 '21 at 11:25
  • Do you have warnings enabled? I'm seeing `warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]` – Eljay Aug 14 '21 at 17:30
  • duplicates: [Why sizeof(int) is not greater than -1?](https://stackoverflow.com/q/24466857/995714), [Signed/unsigned comparisons](https://stackoverflow.com/q/5416414/995714), [C++ Bigger than oddity](https://stackoverflow.com/q/19349480/995714), [why is -1>strlen(t) true in C?](https://stackoverflow.com/q/30295512/995714), [Why is (sizeof(int) > -1) false? (duplicate)](https://stackoverflow.com/q/34151309/995714) – phuclv Aug 15 '21 at 02:30
  • Does this answer your question? [Is comparing signed and unsigned integer safe?](https://stackoverflow.com/questions/42646743/is-comparing-signed-and-unsigned-integer-safe) – phuclv Aug 15 '21 at 02:31

1 Answers1

4

When you compare a signed integer with an unsigned integer, the compiler implicitly converts the signed value into unsigned, so essentially:

int a = -1;
unsigned int b = 5;

assert(a < b);

is equivalent to:

assert(static_cast<unsigned>(-1) < static_cast<unsigned>(5));

Now, because unsigned integers cannot hold negative values, -1 wraps up back to UINT_MAX due to integer overflow:

assert(UINT_MAX < static_cast<unsigned>(5));

which is obviously false, since UINT_MAX is larger than 5, so the assertion fails.

Ruks
  • 3,886
  • 1
  • 10
  • 22