Для следующего фрагмента:
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
например, сообщать об этом как о правде?
Потому что это было бы бесполезным, недействительным предупреждением. size_t
тип без знака, и из-за того, как работают целочисленные преобразования (см. [conv.integral] / 2), -1
преобразуется (неявно здесь) в size_t
равно SIZE_MAX
,
Рассмотрим тот факт, что это фактическое определение std::string::npos
в libstdc ++:
static const size_type npos = static_cast<size_type>(-1);
Если PVS-Studio предупредил о i != -1
Будет ли это также необходимо предупредить о i != std::string::npos
?
С другой стороны, значение без знака не может быть меньше 0, поскольку оно не имеет знака, поэтому i < 0
скорее всего, не то, что хотел программист, и поэтому предупреждение оправдано.
Это связано с неявные интегральные преобразования в обоих случаях. 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
Когда значение преобразуется в без знака, если это значение не может быть представлено типом без знака, то значение будет преобразовано в значение (или, скорее, ценность) что является представимо и совпадает с исходным значением по модулю количества представляемых значений (что является максимальным представимым значением + 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";
}
В таком случае анализатор выдаст два V547 предупреждения:
(V519 тоже будет проходить, но это не относится к вопросу.)
Итак, первое предупреждение V547 печатается, потому что переменная без знака не может быть меньше нуля. Также не имеет значения, какое значение имеет переменная.
Второе предупреждение выдается, потому что анализатор реагирует на то, что переменной 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:
Анализатор ничего не может сказать о (i != -1)
состояние. Это совершенно нормально, и это может быть, например, сравнение с npos
, как уже заметили.
Я написал это на тот случай, если кто-то решит протестировать исходный пример с помощью PVS-Studio, исключив его. Этот человек будет удивлен, когда увидит два предупреждения, хотя обсуждается, что будет только одно.