"有符号和无符号整数表达式之间的比较"只有无符号整数

时间:2014-11-14 14:50:15

标签: c gcc

此代码不应出现此警告吗?

#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的大小不同,但签名相同。是否有关于我不了解的整数转换的内容?这是gcc输出:

$ 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

如果z是unsigned char我没有收到错误。

2 个答案:

答案 0 :(得分:4)

问题是加法运算符对算术类型执行通常的算术转换。在这种情况下,它会导致对操作数执行整数提升,这会导致unsigned char转换为int,因为signed int可以表示unsigned char类型的所有值。

相关主题Why must a short be converted to an int before arithmetic operations in C and C++?解释了促销的基本原理。

答案 1 :(得分:1)

C有一个名为“整数推广”的概念。

基本上这意味着所有数学都是在signed int中完成的,除非你真的坚持否则,或者它不合适。

如果我进行了隐式转换,那么您的示例实际上是这样的:

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

所以,现在你看到签名/未签名的不匹配。

不幸的是,单独使用强制转换无法安全地解决此问题。有几个选择:

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

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

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

但是他们都遇到了同样的问题:如果y大于x会怎么样?如果z大于INTMAX会怎么样(不是它会在例子)?

正确正确的解决方案可能如下所示:

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

最后,除非你真的需要额外的位,否则通常最好避免使用无符号整数。