表达式'i <0'始终为假

mlo*_*kot 25 c++ unsigned static-analysis pvs-studio

对于以下代码段:

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

i < 0正如预期的那样,PVS-Studio分析记录第一个条件的警告:

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

例如,为什么PVS不会发出关于第二个,也是可疑情况的警告,并将其i != -1报告为总是如此?

小智 36

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

考虑一下这是std::string::nposlibstdc ++中的实际定义:

static const size_type  npos = static_cast<size_type>(-1);
Run Code Online (Sandbox Code Playgroud)

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

另一方面,无符号值永远不会小于0,因为它是无符号的,因此i < 0很可能不是程序员想要的,因此警告是有保证的.

  • 我希望有关于隐式转换的警告,这可能是无意的 (7认同)
  • 关于`some_unsigned_variable!= -1`的警告不会没用!在代码中使用它作为一个成语确实是一个令人讨厌的**,但在代码中可能非常有用,可以帮助别人找到一个bug.但是,使用负常量和无符号类型的代码往往会出现在编译器和平台头文件中,因此必须清除这些代码以不触发误报警告或使用某些`#pragmas`来禁用它或其他任何东西. (5认同)
  • @Kaz:作为代码审核者,我会粗略地对无符号变量和-1进行直接比较.代码将具有两个明确含义中的一个,取决于无符号值是否足够大以避免提升,但如果它明确了它实际要求的内容,我会认为代码更清晰,例如,比较`(uint32_t)-1`如果这就是你想要的. (3认同)
  • @ratchetfreak实际上可能更有说服力[this](https://godbolt.org/g/Fz6yxC). (2认同)

Bat*_*eba 22

这是由于两种情况下的隐式积分转换.A size_t 必须是至少16位的无符号类型,在您的情况下,它的大小足够大.int如果一个参数是size_t和其他的int,则该int参数被转换为size_t.

评估时i < 0,0转换为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


eer*_*ika 7

当一个值转换为无,如果该值不是由无符号的类型表示的,则该值将被转换为一个值(或者说,值),其表示的,并且是全等到原始值模的数量可表示的值(最大可表示值+ 1 == 2 n,其中n是位数).

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

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

  • >*没有什么可以警告*废话.由于操作符对面的无符号类型,将"-1"转换为非常大的值,这可能是令人惊讶的.各种各样的正确,符合标准的结构都有很多警告.此外,此处未完全指定行为; 结果是实现定义的.如果`size_t`是16位宽,则得到65535,依此类推; 漂亮且可移植的`-1`常量已变为编译器特定的数字. (2认同)