25

对于以下代码段:

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

4 回答 4

36

因为那将是一个无用的、无效的警告。size_t是无符号类型,并且由于整数转换的工作方式(参见 [conv.integral]/2),-1转换(此处隐含)size_t等于SIZE_MAX.

考虑这是std::string::npos在 libstdc++ 中的实际定义这一事实:

static const size_type  npos = static_cast<size_type>(-1);

如果 PVS-Studio 发出警告i != -1,是否也需要发出警告i != std::string::npos

另一方面,无符号值永远不能小于 0,因为它是无符号的,所以i < 0可能不是程序员想要的,因此警告是有道理的。

于 2017-07-31T08:19:26.917 回答
22

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

评估时i < 00将转换为size_t类型。两个操作数都是size_t这样,表达式总是false

在评估i != -1时,-1也将转换为size_t。这个值将是std::numeric_limits<size_t>::max()

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

于 2017-07-31T08:21:00.830 回答
7

当一个值被转换为无符号时,如果该值不能由无符号类型表示,那么该值将被转换为一个可表示的值(或者更确切地说,),并且与原始值对数的模一致可表示值(最大可表示值 + 1 == 2 n其中 n 是位数)。

因此没有什么需要警告的,因为有一些值可能是假的(只要我们只单独分析那个表达式。i总是0,所以条件总是真,但是要能够证明,我们必须考虑到程序的整个执行)。

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

于 2017-07-31T08:27:36.417 回答
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 表达式 'i < 0' 始终为假。无符号类型值永远不会 < 0。consoleapplication1.cpp 15
  • V547 表达式 'i != - 1' 始终为真。控制台应用程序1.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 表达式 'i < 0' 始终为假。无符号类型值永远不会 < 0。consoleapplication1.cpp 22

分析仪无法说明(i != -1)情况。这是完全正常的,例如,它可以是与 的比较npos,正如已经注意到的那样。

如果有人决定使用 PVS-Studio 测试源示例,我写了这个,把它排除在外。当他看到两个警告时,这个人会感到惊讶,尽管有人讨论过只有一个。

于 2017-08-01T14:04:59.983 回答