Search code examples
c++integer

Why is there a signedness issue when comparing uint16_t and unsigned int?


I have a code like this :

#include <iostream>
using std::cout;
using std::endl;

int main() {
    uint16_t a = 0;
    uint16_t b = 0;

    if ( a - b < 3u )
    {
        cout << "cacahuète" << endl;
    }
    return 0;
}

When I compile it using g++ with -Wall, I get :

temp.cpp: In function ‘int main()’:
temp.cpp:9:13: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
    9 |  if ( a - b < 3u )
      |       ~~~~~~^~~~

That warning doesn't show up if I write if ( a - b < static_cast<uint16_t>(3u) ) instead.

  • So what's going on, here ? Where does the int come from?
  • Can this actually result in an incorrect behavior?
  • Is there a less verbose way to silence it? (or a less verbose way to write a uint16_t literal?)

Solution

  • So what's going on, here ? Where does the int come from?

    Integer promotion is going on here. On systems where std::uint16_t is smaller than int, it will be promoted to int when used as an operand (of most binary operations).

    In a - b both operands are promoted to int and the result is int also. You compare this signed integer to 3u which is unsigned int. The signs differ, as the compiler warns you.

    That warning doesn't show up if I write if ( a - b < static_cast<uint16_t>(3u) ) instead.

    Here, the right hand operand is also promoted to int. Both sides of comparison are signed so there is no warning.

    Can this actually result in an incorrect behavior?

    if ( a - b < static_cast<uint16_t>(3u) ) does have different behaviour than a - b < static_cast<uint16_t>(3u). If one is correct, then presumably the other is incorrect.

    Is there a less verbose way to silence it? (or a less verbose way to write a uint16_t literal?)

    The correct solution depends on what behaviour you want to be correct.


    P.S. You forgot to include the header that defines uint16_t.