13

我有以下简单的 C++ 代码:

#include "stdafx.h"
int main()
{
    int a = -10;
    unsigned int b = 10;
    //  Trivial error is placed here on purpose to trigger a warning.
    if( a < b ) {
        printf( "Error in line above: this will not be printed\n" );
    }
    return 0;
}

使用 Visual Studio 2010(默认 C++ 控制台应用程序)编译,它warning C4018: '<' : signed/unsigned mismatch" on line 7 按预期提供(代码有逻辑错误)。

但是如果我unsigned int b = 10;改成const unsigned int b = 10;警告就消失了!这种行为有什么已知的原因吗?gcc无论const.

更新

我可以从评论中看到很多人建议“它只是以某种方式进行了优化,所以不需要警告”。不幸的是,需要警告因为我的代码示例有实际的逻辑错误仔细放置以触发警告:该print语句将不会被调用,无论它-10实际上小于10. 这个错误是众所周知的,“签名/未签名警告”正是为了找到这样的错误而引发的。

更新

我还可以从评论中看到,很多人在我的代码中“发现”了一个有符号/无符号逻辑错误并正在解释它。哪里不需要这样做 - 这个错误纯粹是为了触发警告,是微不足道的(-10(unsigned int)-10认为是0xFFFFFFFF-10)并且问题与它无关:)。

4

1 回答 1

9

这是一个 Visual Studio 错误,但让我们从不是错误的方面开始。

当时适用的 C++ 标准的第 5 节注 9首先讨论了如果操作数具有不同位宽时该怎么办,然后再讨论如果它们相同但符号不同该怎么办:

...否则,如果无符号整数类型的操作数的等级大于或等于另一个操作数类型的等级,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。

这是我们了解到比较必须在无符号算术中进行的地方。我们现在需要了解这对值 -10 意味着什么。

4.6 节告诉我们:

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2 n 其中 n 是用于表示无符号类型的位数)。[注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。— 尾注] 3 如果目标类型是有符号的,则如果它可以在目标类型(和位域宽度)中表示,则值不变;否则,该值是实现定义的。

正如你所看到的,一个特定的相当高的值(4294967286,或 0xFFFFFFF6,假设unsigned int是一个 32 位数字)正在与 10 进行比较,因此标准保证它printf实际上永远不会被调用。

现在您可以相信我,在这种情况下,标准中没有要求进行诊断的规则,因此编译器可以自由地不发布任何内容。(事实上​​,有些人写-1的目的是产生一个全一的位模式。其他人用于迭代数组,这会导致和int之间的有符号/无符号比较。丑陋,但保证编译。)size_tint

现在 Visual Studio 会“自愿”发出一些警告。

这会导致默认设置下已经出现警告(级别 3):

int a = -10;
unsigned int b = 10;
if( a < b ) // C4018
{
    printf( "Error in line above: this will not be printed\n" );
}

以下要求/W4获得警告。请注意,警告已重新分类。它从警告C4018更改为警告C4245。这显然是设计使然。破坏比较的逻辑错误几乎总是比看似适用于正-正比较但因正-负比较而崩溃的逻辑错误要小。

const int a = -10;
unsigned int b = 10;
if( a < b ) // C4245
{
    printf( "Error in line above: this will not be printed\n" );
}

但是您的情况却有所不同:

int a = -10;
const unsigned int b = 10;
if( a < b ) // no warning
{
    printf( "Error in line above: this will not be printed\n" );
}

而且没有任何警告。(好吧,-Wall如果你想确定,你应该重试。)这是一个错误。微软对此表示

感谢您提交此反馈。这是我们应该发出 C4018 警告的场景。不幸的是,鉴于我们现有的资源,这个特定问题的优先级不够高,无法在下一个版本中修复。

出于好奇,我使用 Visual Studio 2012 SP1 进行了检查,发现缺陷仍然存在 - 没有使用-Wall.

于 2013-03-25T21:40:43.833 回答