>
>
>
V560. Part of conditional expression is…


V560. Part of conditional expression is always true/false.

Анализатор обнаружил потенциально возможную ошибку внутри логического условия. Часть логического выражения всегда истинно и оценено как опасное.

Рассмотрим пример:

#define REO_INPLACEACTIVE (0x02000000L)
...
if (reObj.dwFlags && REO_INPLACEACTIVE)
  m_pRichEditOle->InPlaceDeactivate();

Программист хотел проверить состояние определенного бита в переменной dwFlags. Но из-за опечатки он написал оператор '&&', вместо оператора '&'. Корректный код:

if (reObj.dwFlags & REO_INPLACEACTIVE)
  m_pRichEditOle->InPlaceDeactivate();

Рассмотрим другой пример:

if (a = 10 || a == 20)

Случайно вместо оператора сравнения '==' написан оператор присваивания '='. С точки зрения языка Си++, это выражение будет идентично выражению вида "if (a = (10 || a == 20))".

Выражение "10 || a == 20" анализатор считает опасным, так как левая его часть представляет собой константу. Корректный код:

if (a == 10 || a == 20)

Иногда предупреждение V560 выявляет не ошибку, а просто избыточный код. Рассмотрим пример:

if (!mainmenu) {
  if (freeze || winfreeze ||
      (mainmenu && gameon) ||
      (!gameon && gamestarted))
    drawmode = normalmode;
}

Анализатор предупредит, что в подвыражении (mainmenu && gameon) переменная mainmenu всегда равна 0. То, что переменная mainmenu равна нулю, следует из вышестоящей проверки " if (!mainmenu)". Этот код может быть вполне корректен. Однако он избыточен, и лучше его упростить. Это сделает программу более простой для понимания другими разработчиками.

Упрощенный вариант кода:

if (!mainmenu) {
  if (freeze || winfreeze ||
      (!gameon && gamestarted))
    drawmode = normalmode;
}

Рассмотрим более интересный случай.

int16u Integer = ReadInt16u(Liste);
int32u Exponent=(Integer>>10) & 0xFF;
if (Exponent==0 || Exponent==0xFF)  // V560
  return 0;

Пользователь, приславший этот пример, был озадачен, почему анализатор выдаёт предупреждение, в котором утверждается, что подвыражение 'Exponent==0xFF' всегда ложное. Давайте разберемся. Для этого нам надо внимательно посчитать.

16-битная беззнаковая переменная 'Integer' имеет диапазон возможных значений [0..0b1111111111111111] или [0..0xFFFF].

При сдвиге вправо на 10 бит, диапазон возможных значений уменьшается: [0..0b111111] или [0..0x3F].

Далее выполняется операция '& 0xFF'.

В результате, никак невозможно получить значение '0xFF'. Максимум, это будет '0x3F'.

Ряд конструкций на языке Си++ анализатор считает безопасными, даже если в них часть выражения представляется константой. Примеры некоторых ситуаций, когда анализатор не считает код опасными:

  • подвыражение содержит операторы sizeof(): if (a == b && sizeof(T) < sizeof(__int64)) {};
  • выражение находится в макросе: assert(false);
  • сравниваются две числовых константы: if (MY_DEFINE_BITS_COUNT == 4) {};
  • и так далее.

Особые настройки диагностики V560

По дополнительной просьбе пользователей появилась возможность управлять поведением диагностики V560. В общем заголовочном файле или pvsconfig-файле можно написать комментарий специального вида:

//+V560 ENABLE_PEDANTIC_WARNINGS

Режим 'ENABLE_PEDANTIC_WARNINGS' ослабляет исключения диагностики. Рассмотрим пример:

void foo()
{
  bool debugCheck = false; // maybe in macros
  if (x)
  {
    if (debugCheck)
    {
      ....
    }
  }
}

По умолчанию анализатор не будет считать такой код опасным, так как часто он пишется для отладки. Комментарий позволит ослабить исключение диагностики, чтобы анализатор мог сообщить о проблеме.

Данная диагностика классифицируется как:

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V560.