表达'i< 0'总是假的

时间:2017-07-31 08:17:32

标签: c++ static-analysis unsigned pvs-studio

对于以下代码段:

size_t i = 0;
std::wstring s;
s = (i < 0)   ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";

PVS-Studio分析会按预期为第一个条件i < 0记录警告:

V547 Expression 'i < 0' is always false. Unsigned type value is never < 0. test_cpp_vs2017.cpp 19

为什么PVS不会发出任何关于第二个,也是可疑情况的警告i != -1,例如报告它始终为真?

4 个答案:

答案 0 :(得分:36)

因为那是一个无用的,无效的警告。 size_t是无符号类型,由于整数转换的工作方式(请参阅[conv.integral] / 2),-1转换(隐式在此处)到size_t等于{{ 1}}。

考虑这是libstdc ++中SIZE_MAX的实际定义:

std::string::npos

如果PVS-Studio警告static const size_type npos = static_cast<size_type>(-1); ,是否还需要警告i != -1

另一方面,无符号值永远不会小于0,因为它是无符号的,因此i != std::string::npos可能不是程序员想要的,因此警告是有保证的。

答案 1 :(得分:22)

这是由于两种情况下的隐式积分转换SomeClass 必须是至少16位的无符号类型,在您的情况下,它的大小足够大。 size_t如果一个参数为int而另一个参数为size_t,则int参数将转换为int

评估size_t时,i < 0会转换为0类型。两个操作数均为size_t,因此表达式始终为size_t

评估false时,i != -1也会转换为-1。该值为size_t

参考:http://en.cppreference.com/w/cpp/language/implicit_conversion

答案 2 :(得分:7)

当值转换为无符号时,如果无符号类型无法表示该值,则该值将转换为所在的值(或者更确切地说, 值) 可表示,并且与原始值一致,以可表示值的数量为模(这是最大可表示值+ 1 == 2 n ,其中n是位数)。

因此没有什么可以警告的,因为有一些值可能是错误的条件(只要我们只分析该表达式。i总是0,所以条件总是为真,但为了能够证明这一点,我们必须考虑整个程序的执行情况。)

-1与m - 1模m一致,因此-1总是转换为最大可表示值。

答案 3 :(得分:1)

有正确的重要答案,但我想作一些澄清。不幸的是,测试示例不正确。我们可以这样写:

void F1()
{
  size_t i = 0;
  std::wstring s;
  s = (i < 0)   ? L"ABC" : L"DEF";
  s = (i != -1) ? L"ABC" : L"DEF";
}

在这种情况下,分析仪会发出两个V547警告:

  • V547表达&#39; i&lt; 0&#39;总是假的。无符号类型值永远不会 &LT; 0. consoleapplication1.cpp 15
  • V547 Expression&#39; i!= - 1&#39;总是 真正。 consoleapplication1.cpp 16

V519也会发生,但与问题无关。)

因此,第一个V547警告是打印,因为无符号变量不能小于零。变量具有什么价值也无关紧要。 发出第二个警告是因为分析器对0赋予变量i的反应,并且该变量在任何地方都不会改变。

现在让我们编写另一个测试示例,以便分析器对变量i的值一无所知:

void F2(size_t i)
{
  std::wstring s;
  s = (i < 0)   ? L"ABC" : L"DEF";
  s = (i != -1) ? L"ABC" : L"DEF";
}

现在只有一个V547警告:

  • V547表达&#39; i&lt; 0&#39;总是假的。无符号类型值永远不会&lt; 0. consoleapplication1.cpp 22

分析仪可以对(i != -1)条件一无所知。这是完全正常的,例如,它可以与npos进行比较,正如已经注意到的那样。

如果有人决定使用PVS-Studio测试一个源代码示例,那么我就写下了这个问题。当他看到两个警告时,这个人会感到惊讶,尽管有人会讨论只会有一个警告。