GCC在使用==操作符时,对于有符号变量和无符号字面量的组合不会发出警告。

8
下面的代码中,为什么GCC只会对情况1和3发出警告而不是情况2?
我正在使用-Wall和-g标志进行编译。
int main() {

    unsigned int ui = 4;
    int si = 6;

    if (si == ui ) { // Warning comparison b/w signed and unsigned
        printf("xxxx");
    }

    if (si == 2U ) { // No Warning --- WHY ???
        printf("xxxx");
    }

    if (si > 2U ) { // Warning comparison b/w signed and unsigned
        printf("xxxx");
    }

    return 0;
}
3个回答

4

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html:

在-Wconversion部分:

不要对显式强制类型转换(例如abs ((int) x)ui = (unsigned)-1)发出警告,或者如果转换后的值未更改,例如abs (2.0)

由于2U是字面值,因此gcc知道:

  • 如果si < 0,那么(unsigned) si >= 2^31,因此s1 != 2U
  • 如果si > 0,那么(unsigned) sisi具有相同的值,因此当且仅当si == 2时,(unsigned) si == 2U

总之,将带符号的si与字面值2U进行比较等同于将si2进行比较,即si == 2U的结果不会因将si转换为unsigned而改变。

如果与32位无符号整数中最大的值2^32-1(4294967295U)进行比较,该值在int中不可表示,则即使si本身为负,它也可能等于该值,这可能不是您想要的,因此使用-Wextra选项会生成警告。


1
可能是因为在带符号和无符号类型重叠的范围内,使用常量进行等式比较时没有歧义。
如果我将其更改为
if (si == 2147483648U ) { printf("xxxx"); }
我会收到警告
(实际上,在我得到你报告的警告之前,我必须添加-Wextra)

0
Chris,感谢你的回答。我认为它指向了原因。我的最初想法是U后缀会导致该文字面量提升为无符号类型,但我认为只有当数字大于INT_MAX_32即> 2147483647时,它才会被提升为无符号类型。

它确实被“提升”为无符号,但当其值小于2^31-1时没有任何区别。 - Ryan Li
@ryanli:如果它总是被提升为无符号类型,那么si == 2U也应该会触发警告。为什么2147483647是一个神奇的点,在只有-Wall标志的情况下,gcc应该开始抛出警告。我想我不理解你最初的回答。 - nisah
因为2U是一个字面量,虽然si是有符号的,但gcc在编译时清楚地知道可以将si2U的值进行比较而不会失去精度:如果si本身是负数,则在提升为无符号数后它不等于2U。但对于大于2^31-1的字面量值,gcc会发出警告,因为如果si为负数,则可能等于该字面量,这可能不是您期望的结果。而-Wall不会发出任何警告,正如我回答中的链接所示。 - Ryan Li

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接