此代码不应出现此警告吗?
#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
我没有收到错误。
答案 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")
最后,除非你真的需要额外的位,否则通常最好避免使用无符号整数。