C++ 有符号/无符号比较

C++ 有符号/无符号比较,c++,visual-studio-2005,comparison,unsigned,signed,C++,Visual Studio 2005,Comparison,Unsigned,Signed,我试图理解为什么下面的代码没有在指定的位置发出警告 //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 wa

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

//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;
//来自limits.h
#定义UINT_MAX 0xffffffff/*最大无符号整数值*/
#定义INT_MAX 2147483647/*最大(有符号)INT值*/
/*=0x7fffffff*/
int a=int_MAX;
//_int64 a=INT_MAX;//使所有警告消失
无符号整数b=UINT_MAX;
boolc=假;

如果(a-1==(未签名)-1
。对于其他比较,它很重要,例如,以下是正确的:
-1>2U

编辑:参考:

5/9:(表达)

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

  • 如果有的话 操作数的类型为长双精度 其他应转换为长 加倍
  • 否则,如果任一操作数 一个是双倍的,另一个是双倍的 转换成双倍
  • 否则,如果 两个操作数中的一个为浮点,另一个为浮点 应转换为浮动
  • 否则,整体促销 (4.5)应在两个 操作数(0.54)
  • 然后,如果任意一个操作数 无符号长,则另一个应为 转换为无符号长字符
  • 否则,如果一个操作数是长的 int和另一个无符号int,然后 如果一个长整型可以表示所有 无符号int的值 无符号整数应转换为整数 长整型;否则,两个操作数 应转换为无符号长字符 内部的
  • 否则,如果任一操作数为 长,另一个应转换为 长
  • 否则,如果任一操作数 如果未签名,则另一个应为 已转换为未签名
4.7/2:(积分转换)

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

EDIT2:MSVC警告级别

当然,MSVC不同警告级别的警告是由开发人员做出的选择。在我看来,他们关于有符号/无符号相等与较大/较小比较的选择是有意义的,这当然是完全主观的:

-1==-1
的意思与
-1==(未签名)-1
相同-我发现这是一个直观的结果


-1<2
并不意味着与
-1<(无符号)2
相同-乍一看,这不太直观,IMO应该得到一个“更早”的警告。

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

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

4位示例:

1111=15?还是-1

所以如果你有1111<0001。。。这是模棱两可的


但是如果你有1111==1111。。。这是同样的事情,尽管你不是故意的。

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


对我来说,奇怪的是编译器没有在a==((int)b)上警告您。我认为它应该给您一个整数截断警告之类的东西。

下面的示例演示了为什么有符号/无符号警告很重要,程序员必须注意它们

猜猜这段代码的输出

#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;
}
惊讶?在线演示:


底线:相比之下,如果一个操作数是
无符号的
,那么另一个操作数将隐式转换为
无符号的
,如果它的类型是有符号的

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

从C4389的:

//C4389.cpp
//使用:/W4编译
#杂注警告(默认值:4389)
int main()
{
INTA=9;
无符号整数b=10;
如果(a==b)//C4389
返回0;
其他的
返回0;
};
其他答案很好地解释了为什么微软可能会决定对等式运算符进行特殊处理,但我发现如果不提及C4389或C4389,这些答案就没有太大的帮助

<>我也应该提到,如果你要启用C438,你也可以考虑启用C438。不幸的是,C4388没有官方文档,但它似乎以如下表达式出现:

inta=9;
无符号整数b=10;
bool equal=(a==b);//C4388

gcc 4.4.2在使用“-Wall”调用时打印警告这是推测,但可能它优化了所有比较,因为它在编译时知道答案。啊!重新。博巴评论:我打开了所有警告,现在出现了丢失的警告。我认为它应该出现在与其他比较相同的警告级别设置上。@bobah:我真的很讨厌gcc 4.4.2打印该警告(没有办法告诉它只打印不平等的警告),因为所有压制该警告的方法都会让事情变得更糟。默认提升会将-1或~0可靠地转换为任何无符号类型的最高可能值,但如果您通过自己强制转换来消除警告,则必须知道确切的类型。因此,如果您更改了类型(将其扩展为unsigned long long),那么在比较
i is greater than j