warning: comparison between signed and unsigned integer expressions

When uint16_t and uint8_t integers are compared, Arduino IDE gets this warning:

/home/wolfv/Documents/Arduino/demo/uint_types/uint_types.ino: In function 'void setup()':
/home/wolfv/Documents/Arduino/demo/uint_types/uint_types.ino:10:24: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (big == small * small) //warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
^

This is the sketch:

void setup()
{
    uint16_t big;             //unsigned
    uint8_t small = 20;       //unsigned

    big = small * small;      //no warning

    if (big == small * small) //warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    {
        Serial.print("equal");
    }
}

void loop() { }

Output is as expected:

equal

What does the warning mean?

gcc gets no such warning:

$ g++ -w uint_types.cpp

with this program:

#include <iostream>
#include <inttypes.h>

int main()
{
    uint16_t big;
    uint8_t small = 20;

    big = small * small;

    if (big == small * small)
    {
        std::cout << "equal" << std::endl;
    }
}

I think you will find this is because of C++ integer promotion rules.

http://en.cppreference.com/w/cpp/language/implicit_conversion

Bear in mind that an int on this platform is 16 bits, not 32 bits like on larger processors.

"small * small" will be promoted to int, and then you get the warning.

Why not on the bigger platform (your PC)?

-Wsign-compare
Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned.

OK, on the Arduino, the int could produce incorrect results compared to big (they are both 16 bits, and one has a sign). However on your PC, the signed int is 32 bits, and thus won't produce an invalid comparison to an unsigned 16 bit field.

Thanks Nick. It all makes sense now.

So the compiler was implicitly casting small to signed int.
I guess the compiler isn't smart enough to cast to uint16_t.

Explicitly casting small to uint16_t got rid of the warning:

   if (big == (uint16_t)small * small)

wolfv:
I guess the compiler isn't smart enough to cast to uint16_t.

It's nothing to do with being smart. The compiler writers have to follow the C++ standard. If they don't they get into big trouble. If the specs say to promote to int, that is what they have to do.

Bear in mind there are multiple compilers. The only way you get consistent results if you swap from (say) Microsoft compiler to GNU compiler is that the compiler-writers follow the same rules. Even if they don't agree with those rules.