Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

DevDoc - статьи для разработчика ПО под Windows


DevDoc home page
 
   
 

Автор: Кудинов Александр
Последняя модификация: 2007-01-19 20:25:46

Отладка приложений на C++. Часть 3.

Введение

В этой части я хочу закончить описывать методы пассивной отладки и начать рассмотрение более тонких методик. Начало вы можете найти в Части 1 и Части 2.

В процессе разработки программы надо обращать пристальное внимание на мелкие недоработки, которые могут существенно изменить мнение о Вашем продукте. Часто они не влияют на функциональность программы, поэтому в предыдущей части я ссылался на них как «не критические баги». К этой категории можно отнести несоответствие пользовательского интерфейса общепринятым стандартам, хаотическое расположение элементов управления в окнах, разные размеры у однотипных элементов, нестандартное поведение элементов управления и т.п. Все эти мелочи отличают классно написанную программу, которая будет доставлять удовольствие пользователям при работе с ней, от поделки студента на скорую руку. Зачастую ошибки именно этих типов отнимают много времени при доводке программы до коммерческого вида. Я рекомендую обращать внимание на такие «мелочи» с самого начала разработки. Это позволит избежать цейтнота перед сдачей проекта, когда надо сделать множество мелких исправлений. По сути надо постоянно выполнять контроль качества в процессе работы.

К этой же категории надо отнести и низкое быстродействие. С точки зрения отладки не надо заниматься оптимизацией всего кода. Очень часто для программ применимо правило 80/20, т.е. 20% кода выполняются 80% времени. По-возможности надо всегда стараться избегать явных ляпов, которые ведут к ухудшению быстродействия, однако оптимизировать все подряд не стоит по вышеприведенной причине. Мой совет – начинайте заниматься оптимизацией, когда основная функциональность уже отлажена и работает. При оптимизации, я рекомендую использовать профайлеры. Они позволят найти именно те 20% кода (а иногда это всего несколько строк), которые причиняют наибольшее беспокойство. И еще задумайтесь над тем, что наибольший выигрыш в скорости можно получить если выбрать более оптимальный алгоритм, а не путем оптимизации кода.

«Некрасивый код» не виден конечному пользователю, однако он оказывает прямое воздействие на возможность поддерживать и развивать программный продукт. Трудно дать формальное определение того, что же такое «некрасивый код». Для себя я пользуюсь следующими правилами. Если код им соответствует, то он признается качественным:

  • Он понятен даже без комментариев: имеет информативные имена идентификаторов, не содержит сомнительных трюков (если это конечно не жизненно необходимо).
  • Функции и методы помещаются на 1-2 экрана и выполняют строго определенную функцию понятным образом.
  • Программа не содержит одинаковых кусков кода, которые получены простым копированием. Помимо низкой эффективности это может привести к массовым ошибкам, если ошибочный алгоритм был растиражирован по всей программе. Вместо копирование должно практиковаться повторное использование кода.
  • Есть четко прослеживаемая архитектура без лишних взаимодействий между функциональными модулями.

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

Какие бывают отладчики?

Прежде чем рассматривать конкретные методики отладки необходимо разобраться какие бывают отладчики, и чем они различаются.

Современные процессоры имеют несколько уровней привилегий, которые позволяют защитить программы и операционную систему друг от друга. ОС Windows не использует все средства процессора, тем не менее, в Windows весь код делиться на две части – привилегированный и код пользователя. Привилегированный код еще часто называют кодом ядра ОС или уровнем ядра. На этом уровне работает сердце ОС и низкоуровневые драйверы. Этот код имеет доступ ко всем ресурсам системы, поэтому к его стабильности предъявляются повышенные требования.
С другой стороны все программы, динамические библиотеки выполняются на уровне пользователей. Он не имеет прямого доступа к ресурсам системы и должен использовать сервисы ОС для работы с ними. Разделение привилегий выполняется средствами процессора и ядром Windows.

Существуют отладчики двух типов: отладчики пользовательского режима и отладчики уровня ядра.

Отладчики пользовательского режима подходят для большинства программистов. Именно такой отладчик встроен в среду MS Visual Studio. Как следует из его названия, он служит для отладки приложений, которые работают в пользовательском режиме.

Отладчики ядра позволяют отлаживать код драйверов и ядра ОС. Они преимущественно используются разработчиками драйверов.

Отладчики пользовательского режима.

Программисты могут использовать их для отладки любого кода пользовательского режима, включая динамические библиотеки, COM объекты, сервисы и т.п. В основном такие отладчики используют специальный отладочный API. Как только отладчик запускает приложение с помощью этого API, оно переходит в режим отладки. В дальнейшем отладчик получает полный контроль над выполнением такого приложения и полный доступ к его адресному пространству. Помимо отлаживаемого приложения, отладчик может контролировать все процессы, которые им (отлаживаемым приложением) запущены.

Приложение может узнать о наличии отладчика вызовом функции IsDebuggerPresent.

В особую категорию можно выделить отладчики для виртуальных машин. Как правило, программы, которые выполняются в виртуальной машине, могут отлаживаться с помощью API этой среды. Такое API предоставляют виртуальные машины интерпретируемых языков программирования. Например, Java, С#, Managed C++, Perl, Visual Basic и т.п. Фактически это тоже отладчики пользовательского режима, которые используют API виртуальной машины, а не API ОС.

Отладчики уровня ядра

Эти отладчики управляют ходом выполнения программы (ядра и драйверов) путем прямого управления процессором. Поэтому, когда отладчик останавливается на точке останова – все процессы в системе останавливаются. Активным остается только отладчик. Это вызывает некоторые неудобства использования. Например, нельзя воспользоваться другой программой, пока вы находитесь в отладчике.

Это ограничение можно обойти, если использовать удаленную отладку. На одном компьютере запускается отладчик уровня ядра, который по-прежнему может полностью блокировать систему, а на другом компьютере работает пользовательский интерфейс для этого отладчика. Т.к. интерфейс функционирует на пользовательском уровне, программист может пользоваться справочной системой, дополнительными утилитами и т.п.

Отладчики уровня ядра имеют доступ ко всем ресурсам компьютера, поэтому с помощью них можно отлаживать и код на пользовательском уровне. Этот путь менее удобен, чем использование специально разработанных для этих целей отладчиков пользовательского режима. Им часто пользуются взломщики, которые хотят обойти защиту программы. Также такое использование оправдано, если надо отследить взаимодействие кода пользовательского режима и ядра ОС. Фактически отлаживается оба типа кода одновременно.

Начинаем отладку

Далее мы будем рассматривать техники отладки с помощью отладчика пользовательского уровня, который встроен в среду MS Visual Studio .Net 2003. Это очень удобный инструмент, особенно в последних версиях продукта от Майкрософт. Он позволяет отлаживать приложения, написанные на разных языках программирования (ЯП). В данной статье я буду фокусироваться только на C++. Для других языков техники отладки аналогичные.

Точки останова

Это самый простой инструмент и одновременно очень мощный. Он позволяет остановить выполнение программы при наступлении некоторого условия. В простейшем варианте программа останавливается, когда выполнение достигает заданной строчки исходного кода. Установить такую точку останова проще не куда. Просто поставьте курсор на нужную строку и нажмите F9 или выберите команду Insert breakpoint из контекстного меню. Точка останова ставиться на инструкции процессора, которая начинает данную строку. Т.о. когда выполнение дойдет до этой точки программа будет остановлена и программист сможет изучить содержимое переменных, памяти процесса, стека вызова и т.п.

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

Точка останова на инструкции самая простая и она не лишена недостатков. Предположим, вы поставили точку останова в середине большого цикла. Тогда программа будет прерываться на каждой итерации, а их может быть несколько сотен. Программист может потратить немало времени пока достигнет нужной ему итерации. Решение проблемы – это условные точки останова. Они отличаются от обычных тем, что отладчик самостоятельно проверяет некоторое условие каждый раз, когда он достигает точки останова. В зависимости от результатов проверки он либо продолжает выполнение, либо приостанавливает работу программы.

Существуют также точки останова, которые ставятся не на инструкции, а на данных. В этом случае отладчик приостанавливает программу, если ячейка памяти была изменена. Это очень мощный инструмент, который позволяет искать места, в которых нарушается целостность данных. Этот тип точек останова в полной мере реализуют отладчики уровня ядра, т.к. используют для этого аппаратные возможности процессора. Это обеспечивает высокую производительность. Возможности отладчиков уровня пользователя несколько скромнее, но и они позволяют выполнять такой трюк.

В следующей части я подробно опишу точки останова всех типов.

Продолжение следует…

Copyright (C) Kudinov Alexander, 2006-2007

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


В избранное