Подтвердить что ты не робот

Выражение 'i <0' всегда ложно

Для следующего фрагмента:

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 сообщает об этом, как всегда, например?

4b9b3361

Ответ 1

Потому что это было бы бесполезным, недействительным предупреждением. size_t является неподписанным типом, и из-за того, как работают целочисленные преобразования (см. [conv.integral]/2), -1 преобразованный (неявно здесь) в size_t равен SIZE_MAX.

Рассмотрим тот факт, что это фактическое определение std::string::npos в libstdС++:

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

Если PVS-Studio предупредил о i != -1, не нужно ли также предупреждать о i != std::string::npos?

С другой стороны, значение unsigned никогда не может быть меньше 0, из-за того, что оно является неподписанным, поэтому i < 0 скорее всего не то, что хотел программист, и, следовательно, предупреждение было оправданным.

Ответ 2

Это связано с неявными интегральными преобразованиями в обоих случаях. A size_t должен быть неподписанным типом не менее 16 бит, и в вашем случае он имеет достаточный размер cf. int, что если один аргумент size_t, а другой a 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

Ответ 3

Когда значение преобразуется в unsigned, если это значение не представляется непознанным типом, тогда значение будет преобразовано в значение (или, скорее, значение), которое является представимым, и сравнимо с исходным значением по модулю число представляемых значений (которое является максимальным представимым значением + 1 == 2 n где n - количество бит).

Поэтому не о чем предупреждать, потому что есть какое-то значение, для которого условие может быть ложным (пока мы анализируем это выражение отдельно. i всегда 0, поэтому условие всегда истинно, но чтобы доказать, что мы должны учитывать все исполнение программы).

-1 сравнима с m - 1 по модулю m, поэтому -1 всегда преобразуется в максимальное представимое значение.

Ответ 4

Были правильные важные ответы, но я хотел бы сделать некоторые разъяснения. К сожалению, тестовый пример был сформирован неправильно. Мы можем написать так:

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' всегда правда. consoleapplication1.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, не учитывая его. Этот человек будет удивлен, увидев два предупреждения, хотя обсуждается, что будет только один.