Урок №26. Отладка программ: степпинг и точки останова



Книга Урок №26. Отладка программ: степпинг и точки останова

Удивительно, что программирование может быть сложным и содержать множество ошибок. Ошибки обычно делятся на две категории: синтаксические и семантические.

Типы ошибок

Ошибка в синтаксисе возникает, когда вы пишете код, который не соответствует правилам грамматики языка C++. Например, пропущенные точки с запятой, необъявленные переменные, непарные круглые или фигурные скобки и так далее. В данном коде содержатся несколько синтаксических ошибок:1

#include ; // директивы препроцессора не заканчиваются точкой с запятой

int main ( )

{

std : cout < "Hi there; << x; // недействительный оператор (:), незаконченное предложение (пропущено " ) и необъявленная переменная

return 0 // пропущена точка с запятой в конце стейтмента

}

Радостно, что компилятор обнаруживает такие недочеты и информирует об них в виде предупреждений или ошибок.

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

Иногда возникают ситуации, когда программа может выйти из строя, например, при попытке деления на ноль:

#include

int main ( )

{

int a = 10 ;

int b = 0 ;

std :: cout << a << " / " << b << " = " << a / b ; // делить на 0 нельзя

return 0 ;

}

Иногда это может привести к ошибочным выводам:

#include

int main ( )

{

std :: cout << "Hello, word!" ; // орфографическая ошибка

return 0 ;

}

Или выполнять совсем другие действия, не соответствующие задаче:

#include

int add ( int x , int y )

{

return x - y ; // функция должна выполнять сложение, но выполняет вычитание

}

int main ( )

{

std :: cout << add ( 5 , 3 ) ; // должно быть 8, но результат - 2

return 0 ;

}

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

В приведенных выше примерах ошибки можно обнаружить довольно легко. Однако в большинстве программ, где количество строк кода превышает 40, обнаружить семантические ошибки простым просмотром кода будет непросто.

Отладчик приходит к нам на помощь в этом случае.

Отладчик

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

Ранние версии дебаггеров, такие как GDB, предлагали пользователю интерфейс командной строки, где необходимо было вводить специальные команды для начала работы. Современные дебаггеры уже обладают «графическим» интерфейсом, что значительно упрощает взаимодействие с ними. В настоящее время практически все современные IDE включают в себя встроенные отладчики. Это означает, что можно использовать одну среду разработки как для написания кода, так и для его отладки (вместо постоянного переключения между различными программами).

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

Перед тем как продолжить, убедитесь, что вы работаете в режиме отладки "Debug". Все изображения этого урока сделаны в среде Visual Studio 2019.

Степпинг

Степпинг (или "шаговое выполнение") - это функция отладчика, которая позволяет выполнять код пошагово, т.е. по одной строке за раз. Возможно использование трех команд степпинга:

Давайте рассмотрим каждую из этих команд поочередно.

Команда «Шаг с заходом»

Группа "Шаг с заходом" (англ. "Step into") осуществляет выполнение указанной строки кода. В случае, если эта строка представляет собой вызов функции, то "Шаг с заходом" открывает функцию и переносит выполнение в начало этой функции.

Давайте изучим элементарную программу:

#include

void printValue ( int nValue )

{

std :: cout << nValue ;

}

int main ( )

{

printValue ( 5 ) ;

return 0 ;

}

Как вы уже знаете, когда программа запускается, она начинает выполнение с вызова основной функции main(). Если мы хотим отлаживать код внутри функции main(), то давайте начнем с использования команды "Шаг с заходом".

Для отладки в Visual Studio следует перейти в раздел "Отладка" и выбрать опцию "Шаг с заходом" (или воспользоваться горячей клавишей F11):

Если вы работаете с другой средой разработки, отыщите в панели инструментов опцию "Step Into/Шаг с заходом" и активируйте её.

После выполнения указанных действий произойдет два события. Во-первых, поскольку наше приложение представляет собой консольную программу, откроется консольное окно. Оно будет пустым, поскольку мы еще не выводили никакую информацию. Во-вторых, вы увидите специальный маркер слева от открывающей скобки функции main(). В среде разработки Visual Studio данным маркером является желтая стрелочка (если вы используете другую IDE, то появится что-то аналогичное):

Маркер-стрелка показывает на следующую строку, которая будет выполнена. По мнению отладчика, следующей строкой, которая будет выполнена, является открывающая фигурная скобка функции main(). Если выбрать "Шаг с заходом" еще раз, стрелка переместится на следующую строку:

Это означает, что следующей строкой, которая будет выполнена, будет вызов функции printValue(). Повторите выбор «Шаг с заходом». Поскольку printValue() является вызовом функции, мы перейдем к началу функции printValue():

Для того чтобы открыть фигурные скобки и вызвать функцию printValue(), выберите опцию "Шаг с заходом" еще раз. На этом шаге стрелка будет указывать на строку std::cout << nValue;.

Выберите опцию "Шаг с обходом" (F10) и взгляните на число 5, которое появится в консольном окне.

Повторите выбор «Шаг с заходом» для того, чтобы закрыть фигурные скобки функции printValue(). После выполнения функции printValue() выполнение перейдет к функции main(). Обратите внимание, что в функции main() снова будет вызвана функция printValue():

Возможно, кажется, что отладчик собирается повторно выполнить цикл с функцией printValue(), однако на самом деле он просто уведомляет о том, что только что завершил выполнение этой функции.

Два раза выберите опцию "Шаг с заходом". Все строки кода успешно выполнены. Некоторые отладчики автоматически завершают отладку на этом этапе. Однако Visual Studio не прекращает выполнение программы, поэтому если вы используете Visual Studio, выберите "Отладка" > "Остановить отладку" (или нажмите Shift+F5):

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

Команда «Шаг с обходом»

Подобно группе "Шаг с заходом", команда "Шаг с обходом" (или "Step over" на английском) позволяет выполнить следующую строку кода. Если эта строка представляет собой вызов функции, то "Шаг с обходом" выполнит весь код функции одним нажатием и вернет управление после завершения выполнения функции.

Для тех, кто пользуется Code::Blocks: Команда "Step over" в этой среде называется "Next Line".

Давайте рассмотрим пример, применяя данный код:

#include

void printValue ( int nValue )

{

std :: cout << nValue ;

}

int main ( )

{

printValue ( 5 ) ;

return 0 ;

}

Для достижения вызова функции printValue() следует нажать кнопку "Шаг с заходом":

Вместо использования команды "Шаг с заходом" рекомендуется выбрать "Шаг с обходом" (или нажать F10):

При помощи отладчика будет выполнена функция, которая выведет значение 5 в консоль, после чего управление вернется на строку return 0. Все это произойдет всего за одно нажатие.

Функция "Шаг с обходом" позволяет быстро пропустить выполнение кода функций, если мы убеждены в их правильной работе и отладка не требуется.

Команда «Шаг с выходом»

В отличие от двух предыдущих команд, команда "Шаг с выходом" (англ. "Step out") не просто переходит к следующей строке кода. Она выполняет все оставшиеся действия внутри функции, в которой она была вызвана, и возвращает управление только после завершения выполнения функции. Другими словами, "Шаг с выходом" позволяет выйти из функции.

Обратите внимание, пункт меню "Шаг с выходом" будет доступен только после запуска отладки (что можно сделать с помощью одной из двух указанных команд).

Давайте рассмотрим тот же самый пример:

#include

void printValue ( int nValue )

{

std :: cout << nValue ;

}

int main ( )

{

printValue ( 5 ) ;

return 0 ;

}

Продолжайте нажимать кнопку "Шаг с заходом" до тех пор, пока не дойдете до открывающей фигурной скобки функции printValue():

После этого следует выбрать "Отладка" > "Шаг с выходом" (или нажать Shift+F11):

После выполнения кода в консоли появится число 5, а отладчик автоматически перейдет к функции printValue() в главной программе:

Команда «Выполнить до текущей позиции»

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

Однако существуют и другие возможности для эффективной отладки программ, которые предлагают современные отладчики.

Функция "Выполнить до текущей позиции" позволяет быстро выполнить весь код до строки, на которой установлен курсор. После этого управление возвращается к вам, и вы можете продолжить отладку с этой точки более детально. Давайте попробуем применить эту функцию в нашей уже известной программе:

#include

void printValue ( int nValue )

{

std :: cout << nValue ;

}

int main ( )

{

printValue ( 5 ) ;

return 0 ;

}

Укажите указатель на строку std::cout << nValue; внутри функции printValue(), после чего нажмите правой кнопкой мыши и выберите "Выполнить до текущей позиции" (или используйте Ctrl+F10):

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

Команда «Продолжить»

Если вы находитесь в середине отладки вашего кода, вы можете указать отладчику продолжить выполнение программы до ее завершения или до следующей контрольной точки. В Visual Studio данная функция называется "Продолжить" (англ. "Continue"). В других отладчиках она может быть названа "Run" или "Go".

Вернемся к приведенному выше примеру, мы находимся внутри функции printValue(). Нажмите на "Отладка" > "Продолжить" (или F5):

После завершения выполнения, программа выйдет из режима отладки.

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

Остановочные точки (breakpoints) - это специальные метки, при достижении которых отладчик приостанавливает выполнение программы.

Для установки точки останова в Visual Studio нужно нажать правой кнопкой мыши на выбранной строке, затем выбрать "Точка останова" и "Вставить точку останова":

Рядом с текстовой строкой появится маленький круглый маркер:

Для того чтобы сделать программу уникальной, необходимо создать точку останова на строке std::cout << nValue; в представленном выше коде. После этого следует выбрать опцию «Шаг с заходом» для запуска отладки и затем нажать «Продолжить». Вы увидите, что вместо завершения выполнения программы и остановки отладки, отладчик остановится именно в той точке, которую вы указали.

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

182   0  

Comments

    Ничего не найдено.