Чтобы не откладывать на потом, продолжу рассказывать о своем опыте использования статических анализаторов кода.
Попробовав Klocwork, я попытался заинтересовать им руководство, но главным остановочным критерием послужила цена в 30 тысяч евро, все остальное было уже не важно.
Однако кто-то вдруг вспомнил, что однажды компания уже приобрела лицензию на какой-то анализатор кода.
Этим анализатором оказался PC-Lint. Оказалось, что им никто не пользуется (дочитав до конца, вы поймете почему), поэтому мне дали лицензию, мол, поиграйтесь, если интересно.
Что ж, система оказалась полной противоположностью Klocwork. Запуск из командной строки, все настройки через параметры или файл конфигурации, список файлов для анализа необходимо подготовить вручную.
Правда, была какая-то интеграция с Visual Studio, которая, однако, позволила нам лишь избежать создания списка файлов.
Конфигурационные файлы по-прежнему приходилось писать «вручную» в текстовом редакторе.
Вывести результаты в текстовый файл.
При запуске из Visual Studio он попадал в консоль студии, откуда по клику можно было перейти к месту предполагаемой проблемы (даже проще!).
Самая большая проблема PC-Lint — количество сообщений.
На сравнительно небольшом проекте при настройках по умолчанию было собрано более 23 тысяч комментариев! Потратив пару дней на просмотр и «отключение» 34 наиболее распространенных и в то же время некритичных классов проблем, мне удалось сократить общее количество комментариев до пяти с половиной тысяч! И конечно, в такой куче легко могут затеряться несколько действительно важных заметок, указывающих на реальное переполнение буфера или использование неинициализированной переменной.
И именно по этой причине купившие его перестали пользоваться инструментом.
Я тоже перестал им пользоваться, потратив несколько дней на копание в тысячах предупреждений, обнаружив, однако, парочку реально критичных проблем и немного улучшив стиль кода.
Вы можете только «отключить» все сообщения определенного типа; нет возможности пометить одно конкретное сообщение как ложное срабатывание.
Разумеется, отслеживания от сборки к сборке нет. Вы можете сосредоточиться только на общем количестве сообщений.
Проблемы, обнаруженные в файлах заголовков, дублируются каждый раз при включении этого файла.
Если файл подключен десять раз, то все десять раз PC-Lint будет отображать сообщения обо всех найденных внутри проблемах.
А если учесть, что он легко находит проблемы даже в файлах самой студии, особенно при реализации STL-контейнеров.
При этом то, как возникает проблема, также никак не показано.
Те.
например, он может сообщить, что в заданном месте можно использовать неинициализированную переменную, но при каких именно условиях это происходит, вы должны догадываться сами (в отличие от Klocwork, который показывает полный путь от начала функции до проблемную точку по всем веткам).
И в довершение всего, это работает только локально.
При работе в команде нет возможности легко и быстро сообщить о найденных проблемах другим (только скопировать текст, увы), и нет возможности запустить его всем участникам (если, конечно, каждый участник не купит отдельная лицензия).
Конечно, у PC-Lint есть и свои преимущества.
Количество сообщений при определенных условиях можно считать плюсом.
Несмотря на то, что большинство сообщений связаны со стилем и почти никогда не указывают на потенциальную проблему, стоит признать, что почти каждое сообщение содержит капельку здравого смысла.
И если (теоретически) исправить все, что предлагает исправить PC-Lint, код явно станет лучше, понятнее и читабельнее.
Но как кто-то сказал в Интернете: «Я хочу программировать на C, а не на Lint!» Пример «косметического» комментария: Был:
PC-Lint видит здесь двусмысленность в прочтении: это a/b*c(a/b)*c или a/(b*c)? Соответственно стало:calib_offset = (int32)(full_offset / full_gain * 100000);
calib_offset = (int32)( (full_offset / full_gain) * 100000);
На мой взгляд, читабельность повысилась! Если проект начинается с нуля и не слишком велик, то при желании можно добиться подхода «Ноль проблем» от PC-Lint. Если на момент первого запуска проект близок к завершению, то «Нуля проблем» достичь будет практически невозможно.
Среди других преимуществ, которые я могу выделить:
- очень хорошее описание для каждого выданного предупреждения (все они представлены в отдельном большом PDF-документе, автоматически перейти к описанию из студии естественно невозможно);
- очень большой набор правил, например, есть правила, написанные по обеим книгам Майерса «Эффективный C++»;
- Возможность гибкой настройки – вы можете включать и отключать каждое правило индивидуально;
- хорошо находит реальные проблемы (их сложно найти среди обилия других сообщений);
- цена намного дешевле, чем у других вариантов (389 долларов за бессрочную лицензию).
switch (SocketID)
{
case SOCKETID_1:
case SOCKETID_2:
break;
case SOCKETID_3:
doSomething();
break;
case SOCKETID_4:
doSomethingElse();
case SOCKETID_5:
doSomethingElseSimilar();
case SOCKETID_6:
doAnotherThing();
break;
default:
return ERR_SERVICE_NOT_SUPPORTED;
}
Стал:
switch (SocketID)
{
case SOCKETID_1:
case SOCKETID_2:
break;
case SOCKETID_3:
doSomething();
break;
case SOCKETID_4:
doSomethingElse();
break;
case SOCKETID_5:
doSomethingElseSimilar();
break;
case SOCKETID_6:
doAnotherThing();
break;
default:
return ERR_SERVICE_NOT_SUPPORTED;
}
Если кто-то не заметил, разрыв слова пропущен дважды;
void main_task(void *p_arg)
{
int status;
// somewhere below…
status = memory_init(&memory_config[0], memory_heap, sizeof(memory_heap));
// and later “status” in never used…
}
Замечание к этому фрагменту кода скорее стилистическое — «Значение переменной status нигде не используется», но, на мой взгляд, не такое уж и бессмысленное — такой код создает ложное убеждение, что результат работы функции Memory_init принимается в расчет. аккаунт где-то, что, однако, не так.
И гораздо «честнее» переписать код вот так, не объявляя неиспользуемую переменную и явно не отбрасывая результат. void main_task(void *p_arg)
{
// some code…
memory_init(&memory_config[0], memory_heap, sizeof(memory_heap));
// some other code
}
Конечно, правильнее было бы проверить результат и предпринять необходимые действия в случае неудачи - но.
это хорошо, когда проект находится на ранней стадии, а изменить архитектуру приложения еще достаточно легко, и не когда проект уже завершен и есть обработка исключений, изначально архитектурно не задумано (Можно проверить результат, но что дальше? Куда его тогда девать, если это сигнализирует о сбое, а вызывающая функция не имеет механизм разрешения исключительных ситуаций?).
И именно поэтому необходим статический анализатор кода, запускаемый регулярно (в идеале после каждой сборки!), вместе с требованием «Ноль предупреждений от анализатора».
Конечно, ни один анализатор не заменит грамотного разработчика, code review и других приемов и методов управления разработкой.
Однако при правильном использовании он определенно может облегчить жизнь всей команде! Теги: #статический анализ кода #PC-lint #проектирование и рефакторинг
-
Rss: Rss Блога
19 Oct, 24 -
Как Облачные Технологии Меняют Мир Спорта
19 Oct, 24 -
Восточные Рукописи Будут Оцифрованы
19 Oct, 24 -
Кодируем Знак Рубля Html
19 Oct, 24 -
Memcached В Php Kohana И Его Тестирование
19 Oct, 24 -
Delivery-Club - Единая Система Заказов
19 Oct, 24 -
Задайте Вопрос Гуру Ит-Индустрии
19 Oct, 24