对于以下代码段:
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
,例如报告它始终为真?
答案 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警告:
(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警告:
分析仪可以对(i != -1)
条件一无所知。这是完全正常的,例如,它可以与npos
进行比较,正如已经注意到的那样。
如果有人决定使用PVS-Studio测试一个源代码示例,那么我就写下了这个问题。当他看到两个警告时,这个人会感到惊讶,尽管有人会讨论只会有一个警告。