web-dev-qa-db-ja.com

式 'i <0'は常にfalseです

次のスニペットの場合:

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たとえば、常に正しいと報告しますか?

25
mloskot

それは無用で無効な警告だからです。 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はプログラマが望んだものではない可能性が高いため、警告が必要です。

36
Fanael

これは、どちらの場合も暗黙の整数変換によるものです。 _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

22
Bathsheba

値を符号なしに変換するときに、その値が符号なしの型で表現できない場合、値はisの値(またはthe value)に変換されます=表現可能で、表現可能な値の数を法とする元の値と一致します(表現可能な最大値+ 1 == 2n ここで、nはビット数です)。

したがって、条件が偽になる可能性のある値があるため、警告するものは何もありません(その式を単独で分析する限り。iは常に0なので、条件は常に真ですが、それを証明できるようにするには、プログラムの実行全体を考慮する必要があります)。

-1はm-1モジュロmと合同であるため、-1は常に表現可能な最大値に変換されます。

7
eerorika

正しい重要な答えがありましたが、いくつか明確化したいと思います。残念ながら、テスト例は誤って作成されました。次のように書くことができます。

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 警告を発行します。

  • V547式 'i <0'は常にfalseです。符号なしの型の値が0未満になることはありません。consoleapplication1.cpp 15
  • V547式 'i!=-1'は常に真です。 consoleapplication1.cpp 16

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つだけになります。

  • V547式 'i <0'は常にfalseです。符号なしの型の値が0未満になることはありません。consoleapplication1.cpp 22

アナライザーは、(i != -1)状態について何も言うことができません。これは完全に正常であり、たとえば、すでに気づいたように、nposとの比較になります。

誰かがPVS-Studioを使用してソースの例をテストすることに決めた場合に備えて、これを書きました。この人は2つの警告を見ると驚かされますが、警告は1つしかないと説明されています。

1
AndreyKarpov