签名/未签名比较

问题描述 投票:82回答:5

我试图理解为什么下面的代码没有在指定的位置发出警告。

//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX  2147483647 /* maximum (signed) int value */
            /* = 0x7fffffff */

int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;

if(a < b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a == b) // no warning <--- warning expected here
    c = true;
if(((unsigned int)a) == b) // no warning (as expected)
    c = true;
if(a == ((int)b)) // no warning (as expected)
    c = true;

我以为这与背景宣传有关,但最后两个似乎不是这样。

在我看来,第一个==比较与其他比较是否是有符号/无符号不匹配?

c++ visual-studio-2005 comparison unsigned signed
5个回答
87
投票

比较有符号和无符号时,编译器会将有符号的值转换为无符号。对于平等,这并不重要,-1 == (unsigned) -1。对于其他比较而言,例如以下是正确的:-1 > 2U

编辑:参考文献:

5/9 :(表达式)

许多期望的二进制运算符算术或枚举操作数类型原因转换和收益结果类型以类似的方式。的目的是产生一个普通的类型,这也是结果的类型。这种模式称为通常算术转换定义如下:

  • 如果有操作数的类型为long double,其他应转换为long双。

  • 否则,如果任何一个操作数是双的,另一个应该是转换为两倍。

  • 否则,如果一个操作数是浮点数,另一个应转换为浮点数。

  • 否则,积分促销(4.5)应在两个54)

  • 然后,如果有一个操作数长期未签名转换为unsigned long。

  • 否则,如果一个操作数为longint和另一个unsigned int,则如果long int可以代表所有无符号整数的值,unsigned int应转换为a长整数否则两个操作数应转换为unsigned longint。

  • 否则,如果任一操作数为长,另一个应转换为长。

  • 否则,如果任何一个操作数未签名,另一个应为转换为无符号。

4.7 / 2 :(积分转换)

如果目标类型是无符号的,结果值最小无符号整数与源整数(模2 n,其中n为用于表示的位数无符号类型)。 [注意:两人间补码表示法转换是概念性的,有位模式无变化(如果有)没有截断)。 ]

EDIT2:MSVC警告级别

当然,对于MSVC的不同警告级别,警告是开发人员做出的选择。正如我所看到的,他们在有符号/无符号相等与更大/更少比较之间的选择是有道理的,这当然是完全主观的:

[-1 == -1的含义与-1 == (unsigned) -1相同-我发现直观的结果。

-1 < 2 不是的含义与-1 < (unsigned) 2相同-乍看之下不太直观,IMO应该得到“较早的警告”。


30
投票

为什么签名/未签名警告很重要,程序员必须注意它们,以下示例演示了这一点。

猜猜此代码的输出吗?

#include <iostream>

int main() {
        int i = -1;
        unsigned int j = 1;
        if ( i < j ) 
            std::cout << " i is less than j";
        else
            std::cout << " i is greater than j";

        return 0;
}

输出:

i is greater than j

惊讶吗?在线演示:http://www.ideone.com/5iCxY

Bottomline:相比之下,如果一个操作数为unsigned,则另一个操作数将隐式转换为unsigned if其类型已签名!


4
投票

==运算符只是进行按位比较(通过简单的除法看是否为0)。

比比较大/小比大得多地依赖于数字的符号。

4位示例:

1111 = 15吗?或-1?

因此,如果您有1111 <0001 ...这是不明确的...

但是如果您有1111 == 1111 ...是同一回事,尽管您并非故意如此。


1
投票

在使用2补码表示值的系统(大多数现代处理器)中,即使它们的二进制形式也相等。这可能就是为什么编译器不抱怨a == b

的原因

对我来说,奇怪的编译器不会在a ==((int)b)]上警告您。我认为它应该为您提供整数截断警告之类的东西。


0
投票

有问题的代码行不会生成C4018警告,因为Microsoft使用了不同的警告编号(即C4389)来处理这种情况,并且默认情况下未启用C4389(即3级)。

© www.soinside.com 2019 - 2024. All rights reserved.