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

问题描述:

此警告不应出现在此代码中吗?“带符号和无符号整数表达式之间的比较”只带有无符号整数

#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

适合我!不要得到一个错误或警告 – Rizier123 2014-11-14 14:51:26

+0

http://stackoverflow.com/questions/17312545/type-conversion-unsigned-to-signed-int-char – Lundin 2014-11-14 15:02:43

+0

@ Rizier123:我一直使用C多年没有这个警告,这就是为什么我甚至不需要知道这一点。我猜gcc直到最近才发出这个警告,所以也许你的gcc版本是不同的? – 2014-11-14 15:16:27

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

相关线程Why must a short be converted to an int before arithmetic operations in C and C++?解释了促销的理由。

+0

我明白了,谢谢,所以可以表示为int的整数被提升为int。这实际上是因为这个警告而令人讨厌的。要么我把整数改为'int',即使它们总是正面的,我使用了一个强制类型,或者我禁用了这个警告。任何想法什么是最好的解决方案? – 2014-11-14 15:12:35

+0

@MatthewMitchell使用强制转换是明确的,而禁用警告可以稍后隐藏可能的问题。 – 2014-11-14 15:20:19

+0

当然,铸造会使代码复杂化。使用'int'代替'unsigned char'和'unsigned short'会更好吗? – 2014-11-14 15:26:34

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"); 

但他们都来自同一个问题的困扰:如果yx大,如果z大于INTMAX(不是它会在示例中)?

一个正确正确的解决方案可能是这样的:

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

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

+0

更准确地说:所有小整数类型隐式整数提升为“int”。用于操作的类型取决于整数提升和平衡(“常用算术转换”)。 – Lundin 2014-11-14 15:06:50

+0

我确实说过“基本上”。 – ams 2014-11-14 15:36:00