Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
GBP
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
V719. The switch statement does not cov…
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Диагностика микро-оптимизаций (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Cтандарт MISRA
Стандарт AUTOSAR
Дополнительная информация
Оглавление

V719. The switch statement does not cover all values of the enum.

5 марта 2015 г.

Анализатор обнаружил подозрительный оператор 'switch'. Выбор варианта осуществляется по переменной enum-типа. При этом рассмотрены не все возможные варианты.

Поясним это на примере:

enum TEnum { A, B, C, D, E, F };
....
TEnum x = foo();
switch (x)
{
  case A: Y(11); break;
  case B: Y(22); break;
  case C: Y(33); break;
  case D: Y(44); break;
  case E: Y(55); break;
}

Перечисление TEnum содержит 6 именованных констант. Но в операторе 'switch' используется только 5 из них. Высока вероятность, что это ошибка.

Такая ошибка часто возникает в ходе рефакторинга. В 'TEnum' добавили константу 'F". После этого какие-то 'switch' поправили, а про какие-то забыли. В результате, значение 'F' начинает обрабатываться неправильно.

Анализатор предупредит о том, что константа 'F' не используется. И тогда программист может исправить оплошность:

switch (x)
{
  case A: Y(11); break;
  case B: Y(22); break;
  case C: Y(33); break;
  case D: Y(44); break;
  case E: Y(55); break;
  case F: Y(66); break;
}

Анализатор выдает предупреждение далеко не всегда, когда в 'switch' используется не все константы из перечисления. Иначе, было бы слишком много ложных срабатываний. Действует целый ряд исключений эмпирического типа. Основные:

  • Есть default-ветка;
  • В перечислении всего 1 или 2 константы;
  • В switch не используется более чем 4 константы;
  • Отсутствующая константа содержит в имени: None, Unknown и т.п.
  • Отсутствующая константа самая последняя в enum и содержит в имени "end", "num", "count" и т.п.

Пользователь может сам задать список имён, которые обозначают последний элемент в перечислении. В этом случае анализатор не использует список имён по умолчанию, такие как "num" или "count". Будут использованы только имена, указанные пользователем. Комментарий, управляющий поведением диагностики V719:

//-V719_COUNT_NAME=ABCD,FOO

Вы можете разметить этот комментарий в одном из файлов, включаемый во все другие. Например, в StdAfx.h.

Описанные исключения являются взвешенным решением, проверенными на практике. Единственное что стоит рассмотреть подробнее, это отсутствие предупреждений, когда есть 'default'. Не всегда это хорошо.

С одной стороны, анализатору нельзя ругаться если константы не используются, но при это есть 'default'. Будет слишком много ложных срабатываний и пользователи просто будут отключать эту диагностику. С другой стороны, весьма типовой ситуацией является, когда в 'switch' следует рассмотреть все варианты, а ветка 'default' используется для отлова аварийных ситуаций. Пример:

enum TEnum { A, B, C, D, E, F };
....
TEnum x = foo();
switch (x)
{
  case A: Y(11); break;
  case B: Y(22); break;
  case C: Y(33); break;
  case D: Y(44); break;
  case E: Y(55); break;
  default:
    throw MyException("Ай! Забыли рассмотреть один из вариантов!");
}

Ошибка может быть обнаружена только на этапе исполнения. Естественно есть желание отловить эту ситуацию и с помощью анализатора. В наиболее ответственных местах кода можно поступить следующим образом:

enum TEnum { A, B, C, D, E, F };
....
TEnum x = foo();
switch (x)
{
  case A: Y(11); break;
  case B: Y(22); break;
  case C: Y(33); break;
  case D: Y(44); break;
  case E: Y(55); break;
  #ifndef PVS_STUDIO
  default:
    throw MyException("Ай! Забыли рассмотреть один из вариантов!");
  #endif
}

Используется предопределённый макрос PVS_STUDIO. Этот макрос отсутствует при компиляции. Поэтому при компиляции исполняемого файла ветка 'default' остается на своём месте и в случае ошибки возникнет исключение.

При проверке кода с помощью PVS-Studio макрос PVS_STUDIO определён и поэтому анализатор не увидит default-ветку. Поэтому он проверит 'switch', обнаружит что не используется константа 'F' и выдаст предупреждение.

Исправленный вариант кода:

switch (x)
{
  case A: Y(11); break;
  case B: Y(22); break;
  case C: Y(33); break;
  case D: Y(44); break;
  case E: Y(55); break;
  case F: Y(66); break;
  #ifndef PVS_STUDIO
  default:
    throw MyException("Ай! Забыли рассмотреть один из вариантов!");
  #endif
}

Описанный подход не очень красив. Однако, если вы очень переживаете за какой-то 'switch' и хотите максимально защитить его, то этот способ вполне подходит.

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

  • CERT-MSC01-C

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

Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять