C++: Signed/unsigned mismatch when only using unsigned types
Asked Answered
H

4

5

When I try to compile the following C++ program using the Visual Studio 2010 C++ compiler (X86) with warning level /W4 enabled, I get a signed/unsigned mismatch warning at the marked line.

#include <cstdio>
#include <cstdint>
#include <cstddef>

int main(int argc, char **argv)
{
    size_t idx = 42;
    uint8_t bytesCount = 20;

    // warning C4389: '==' : signed/unsigned mismatch
    if (bytesCount + 1 == idx)
    {
        printf("Hello World\n");
    }

    // no warning
    if (bytesCount == idx)
    {
        printf("Hello World\n");
    }
}

This confuses me, since I'm only using unsigned types. Since the comparison

bytesCount == idx

causes no such warning, it probably has to do with some strange implicit conversation that happens here.

Thus: what is the reason why I get this warning and by what rules does this conversation happen (if this is the reason)?

Hosanna answered 19/12, 2011 at 19:6 Comment(0)
C
5

1 is an int. The type of an integral arithmetic expression depends on the types involved. In this case, you have an unsigned type and a signed type where the unsigned type is smaller than the signed type. This falls under the C++ standard on expressions (section 5.10 [expr]):

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.

I.e., the type of the expression bytesCount + 1 is int which is signed by default.

Comic answered 19/12, 2011 at 19:19 Comment(0)
G
9

1 is a signed literal. Try bytesCount + 1U.

The compiler is probably creating a temporary value of the signed type due to the addition of signed and unsigned values ( bytesCount + 1 )

Guernica answered 19/12, 2011 at 19:8 Comment(0)
C
5

1 is an int. The type of an integral arithmetic expression depends on the types involved. In this case, you have an unsigned type and a signed type where the unsigned type is smaller than the signed type. This falls under the C++ standard on expressions (section 5.10 [expr]):

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.

I.e., the type of the expression bytesCount + 1 is int which is signed by default.

Comic answered 19/12, 2011 at 19:19 Comment(0)
R
3

Since 1 is of type int the expression bytesCount + 1 is int (signed).

In fact when a type smaller than int is used in a mathematical expression it is promoted to int, so even + bytesCount and bytesCount + bytesCount are considered int and not uint8_t (while bytesCount + 1U is an unsigned int since that is larger than int).

The following program outputs true three times.

#include <iostream>

int main() 
{
    unsigned short s = 1;
    std::cout << (&typeid( s + 1U ) == &typeid(1U)) << std::endl;
    std::cout << (&typeid( + s ) == &typeid(1)) << std::endl;
    std::cout << (&typeid( s + s ) == &typeid(1)) << std::endl;
}
Ringtail answered 19/12, 2011 at 19:9 Comment(0)
T
1

The other answers already tell you that bytesCount + 1 is interpreted as signed int. However, I'd like to add that in bytesCount == idx, bytesCount is also interpreted as signed int. Conceptually, it is first converted to signed int, and it is only converted to unsigned int after that. Your compiler does not warn about this, because it has enough information to know that there is not really problem. The conversion to signed int cannot possibly make bytesCount negative. Comparing bytesCount + 1 is equally valid, equally safe, but just that slight bit more complex to make the compiler no longer recognise it as safe.

Tingey answered 19/12, 2011 at 19:23 Comment(2)
And how to tell compiler to not warn me about such problem, if it's clear from program code that comparation is safe, but I don't want to disable warnings for whole file, and I don't want to make code ugly to avoid it. Does there exists any ways to achieve that?Gielgud
@Gielgud If the compiler is configured to warn for the code, you don't want to change the code (because it'll be uglier), and you don't want to change the compiler's configuration (because it'll suppress useful warnings too), you're not leaving a lot of options open. The only option I can think of that you haven't yet ruled out is hacking on the compiler to improve its analysis.Tingey

© 2022 - 2024 — McMap. All rights reserved.