2

This warning should not appear for this code should it?

#include <stdio.h>

int main(void) {

    unsigned char x = 5;
    unsigned char y = 4;
    unsigned int z = 3;

    puts((z >= x - y) ? "A" : "B");

    return 0;

}

z is a different size but it is the same signedness. Is there something about integer conversions that I'm not aware about? Here's the gcc output:

$ gcc -o test test.c -Wsign-compare
test.c: In function ‘main’:
test.c:10:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  puts((z >= x - y) ? "A" : "B");
          ^
$ gcc --version
gcc (Debian 4.9.1-15) 4.9.1

If z is an unsigned char I do not get the error.

Matthew Mitchell
  • 5,293
  • 14
  • 70
  • 122
  • Works fine for me! Don't get a error or warning – Rizier123 Nov 14 '14 at 14:51
  • http://stackoverflow.com/questions/17312545/type-conversion-unsigned-to-signed-int-char – Lundin Nov 14 '14 at 15:02
  • @Rizier123: I've been using C for years without this warning, which is why I never even needed to know about this. I'm guessing gcc did not give this warning until more recently, so perhaps your gcc version is different? – Matthew Mitchell Nov 14 '14 at 15:16

2 Answers2

4

The issue is that additive operators perform the usual arithmetic conversions on arithmetic types which. In this case it results in the integer promotions being performed on the operands, which results in unsigned char being converted to int since signed int can represent all the values of the type of unsigned char.

A related thread Why must a short be converted to an int before arithmetic operations in C and C++? explains the rationale for promotions.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    I understand thanks, so integers that can be represented as `int` are promoted to `int`... That's quite the nuisance actually because of this warning. Either I change the integers to be `int`, even though they are always to be positive, I use a cast, or I disable the warning. Any ideas what would be the best solution? – Matthew Mitchell Nov 14 '14 at 15:12
  • @MatthewMitchell using the cast is explicit while disabling the warning can hide possible issue later on. – Shafik Yaghmour Nov 14 '14 at 15:20
  • Sure but casts complicate the code. Might using `int` in place of `unsigned char` and `unsigned short` be better? – Matthew Mitchell Nov 14 '14 at 15:26
  • I updated my answer (not this one). The answer is "yes", use an `int` whenever there's a real reason not to; the compiler will end up using one behind the scenes anyway (because C says so, and because CPUs are built that way). – ams Nov 14 '14 at 15:53
  • @MatthewMitchell using *int* would solve the issue, in many cases changing types is not an option due to requirements of the larger project. – Shafik Yaghmour Nov 14 '14 at 15:54
  • Thanks for both answers, I would like to accept both, but since this answer was give first I think it's fair to give the solution to this one – Matthew Mitchell Nov 14 '14 at 17:31
1

C has this concept called "Integer Promotion".

Basically it means that all maths is done in signed int unless you really insist otherwise, or it doesn't fit.

If I put in the implicit conversions, your example actually reads like this:

puts((z >= (int)x - (int)y) ? "A" : "B");

So, now you see the signed/unsigned mismatch.

Unfortunately, you can't safely correct this problem using casts alone. There are a few options:

puts((z >= (unsigned int)(x - y)) ? "A" : "B");

or

puts((z >= (unsigned int)x - (unsigned int)y) ? "A" : "B");

or

puts(((int)z >= x - y) ? "A" : "B");

But they all suffer from the same problem: what if y is larger than x, and what if z is larger than INTMAX (not that it will in the example)?

A properly correct solution might look like this:

puts((y > x || z >= (unsigned)(x - y)) ? "A" : "B")

In the end, unless you really need the extra bit, it usually best to avoid unsigned integers.

ams
  • 24,923
  • 4
  • 54
  • 75
  • More accurately: all small integer types are implicitly integer promoted to `int`. What types that are used for the operation depends on integer promotion and balancing (the "usual arithmetic conversions"). – Lundin Nov 14 '14 at 15:06
  • I did say "basically". – ams Nov 14 '14 at 15:36