次のスニペットの場合:
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
、 予想通り:
V547Expression 'i < 0' is always false. Unsigned type value is never < 0. test_cpp_vs2017.cpp 19
PVSが2番目の、また疑わしい状態に関する警告を発行しない理由i != -1
たとえば、常に正しいと報告しますか?
それは無用で無効な警告だからです。 size_t
は符号なしの型であり、整数変換の動作方法([conv.integral]/2を参照)により、-1
は(暗黙的に)size_t
に変換され、SIZE_MAX
。
これがlibstdc ++のstd::string::npos
の実際の定義であるという事実を考慮してください。
static const size_type npos = static_cast<size_type>(-1);
PVS-Studioがi != -1
について警告した場合、i != std::string::npos
についても警告する必要がありますか?
一方、符号なしであるため、符号なしの値は決して0より小さいことはありません。したがって、i < 0
はプログラマが望んだものではない可能性が高いため、警告が必要です。
これは、どちらの場合も暗黙の整数変換によるものです。 _size_t
_must少なくとも16ビットの符号なしの型である必要があり、あなたの場合は十分なサイズです。 int
は、1つの引数が_size_t
_で、もう1つの引数が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
値を符号なしに変換するときに、その値が符号なしの型で表現できない場合、値はisの値(またはthe value)に変換されます=表現可能で、表現可能な値の数を法とする元の値と一致します(表現可能な最大値+ 1 == 2n ここで、nはビット数です)。
したがって、条件が偽になる可能性のある値があるため、警告するものは何もありません(その式を単独で分析する限り。i
は常に0なので、条件は常に真ですが、それを証明できるようにするには、プログラムの実行全体を考慮する必要があります)。
-1はm-1モジュロmと合同であるため、-1は常に表現可能な最大値に変換されます。
正しい重要な答えがありましたが、いくつか明確化したいと思います。残念ながら、テスト例は誤って作成されました。次のように書くことができます。
void F1()
{
size_t i = 0;
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
}
そのような場合、アナライザーは2つの V547 警告を発行します。
( V519 も行われますが、問題とは関係ありません。)
そのため、符号なし変数はゼロ未満にできないため、最初のV547警告が出力されます。また、変数の値は関係ありません。 2番目の警告は、アナライザーが変数iに0が割り当てられ、この変数がどこでも変更されないことを反応させるために発行されます。
次に、アナライザーが変数i
の値について何も知らないように、別のテスト例を作成します。
void F2(size_t i)
{
std::wstring s;
s = (i < 0) ? L"ABC" : L"DEF";
s = (i != -1) ? L"ABC" : L"DEF";
}
これで、V547の警告は1つだけになります。
アナライザーは、(i != -1)
状態について何も言うことができません。これは完全に正常であり、たとえば、すでに気づいたように、npos
との比較になります。
誰かがPVS-Studioを使用してソースの例をテストすることに決めた場合に備えて、これを書きました。この人は2つの警告を見ると驚かされますが、警告は1つしかないと説明されています。