Как ни странно, программирование может быть сложным и ошибок может быть очень много. Ошибки, как правило, попадают в одну из двух категорий: синтаксические или семантические/смысловые.
Типы ошибок
Синтаксическая ошибка возникает, когда вы пишете код, который не соответствует правилам грамматики языка C++. Например, пропущенные точки с запятой, необъявленные переменные, непарные круглые или фигурные скобки и т.д. В следующей программе есть несколько синтаксических ошибок:
1 2 3 4 5 6 7 |
#include <iostream>; // директивы препроцессора не заканчиваются точкой с запятой int main() { std:cout < "Hi there; << x; // недействительный оператор (:), незаконченное предложение (пропущено ") и необъявленная переменная return 0 // пропущена точка с запятой в конце стейтмента } |
К счастью, компилятор ловит подобные ошибки и сообщает о них в виде предупреждений или ошибок.
Семантическая ошибка возникает, когда код является синтаксически правильным, но делает не то, что задумал программист.
Иногда это может привести к сбою в программе, например, если делить на ноль:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { int a = 10; int b = 0; std::cout << a << " / " << b << " = " << a / b; // делить на 0 нельзя return 0; } |
Иногда это может привести к неверным результатам:
1 2 3 4 5 6 7 |
#include <iostream> int main() { std::cout << "Hello, word!"; // орфографическая ошибка return 0; } |
Либо делать вообще не то, что нужно:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> int add(int x, int y) { return x - y; // функция должна выполнять сложение, но выполняет вычитание } int main() { std::cout << add(5, 3); // должно быть 8, но результат - 2 return 0; } |
К сожалению, компилятор не ловит подобные ошибки, так как он проверяет только то, что вы написали, а не то, что вы хотели этим сделать.
В примерах, приведенных выше, ошибки довольно легко обнаружить. Но в большинстве программ (в которых больше 40 строк кода), семантические ошибки увидеть с помощью простого просмотра кода будет не так-то и легко.
И здесь нам на помощь приходит отладчик.
Отладчик
Отладчик (или «дебаггер», от англ. «debugger») — это компьютерная программа, которая позволяет программисту контролировать выполнение кода. Например, программист может использовать отладчик для выполнения программы пошагово, последовательно изучая значения переменных в программе.
Старые дебаггеры, такие как GDB, имели интерфейс командной строки, где программисту приходилось вводить специальные команды для старта работы. Современные дебаггеры имеют графический интерфейс, что значительно упрощает работу с ними. Сейчас почти все современные IDE имеют встроенные отладчики. То есть, вы можете использовать одну среду разработки как для написания кода, так и для его отладки (вместо постоянного переключения между разными программами).
Базовый функционал у всех отладчиков один и тот же. Отличаются они, как правило, тем, как этот функционал и доступ к нему организованы, горячими клавишами и дополнительными возможностями.
Примечание: Перед тем как продолжить, убедитесь, что вы находитесь в режиме конфигурации «Debug». Все скриншоты данного урока выполнены в Visual Studio 2019.
Степпинг
Степпинг (англ. «stepping») — это возможность отладчика выполнять код пошагово (строка за строкой). Есть три команды степпинга:
Команда "Шаг с заходом"
Команда "Шаг с обходом"
Команда "Шаг с выходом"
Мы сейчас рассмотрим каждую из этих команд в индивидуальном порядке.
Команда «Шаг с заходом»
Команда «Шаг с заходом» (англ. «Step into») выполняет следующую строку кода. Если этой строкой является вызов функции, то «Шаг с заходом» открывает функцию и выполнение переносится в начало этой функции.
Давайте рассмотрим очень простую программу:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> void printValue(int nValue) { std::cout << nValue; } int main() { printValue(5); return 0; } |
Как вы уже знаете, при запуске программы выполнение начинается с вызова главной функции main(). Так как мы хотим выполнить отладку внутри функции main(), то давайте начнем с использования команды «Шаг с заходом».
В Visual Studio, перейдите в меню "Отладка" > "Шаг с заходом"
(либо нажмите F11
):
Если вы используете другую IDE, то найдите в меню команду "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».
Рассмотрим пример, используя следующую программу:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> void printValue(int nValue) { std::cout << nValue; } int main() { printValue(5); return 0; } |
Нажмите «Шаг с заходом», чтобы дойти до вызова функции printValue():
Теперь, вместо команды «Шаг с заходом», выберите «Шаг с обходом» (или F10):
Отладчик выполнит функцию (которая выведет значение 5
в консоль), а затем возвратит нам управление на строке return 0;
. И это всё за одно нажатие.
Команда «Шаг с обходом» позволяет быстро пропустить код функций, когда мы уверены, что они работают корректно и их не нужно отлаживать.
Команда «Шаг с выходом»
В отличие от двух предыдущих команд, команда «Шаг с выходом» (англ. «Step out») не просто выполняет следующую строку кода. Она выполняет весь оставшийся код функции, в которой вы сейчас находитесь, и возвращает контроль только после того, когда функция завершит свое выполнение. Проще говоря, «Шаг с выходом» позволяет выйти из функции.
Обратите внимание, команда «Шаг с выходом» появится в меню «Отладка» только после начала сеанса отладки (что делается путем использования одной из двух вышеприведенных команд).
Рассмотрим все тот же пример:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> void printValue(int nValue) { std::cout << nValue; } int main() { printValue(5); return 0; } |
Нажимайте «Шаг с заходом» до тех пор, пока не перейдете к открывающей фигурной скобке функции printValue():
Затем выберите "Отладка" > "Шаг с выходом"
(либо Shift+F11
):
Вы заметите, что значение 5
отобразилось в консольном окне, а отладчик перешел к вызову функции printValue() в main():
Команда «Выполнить до текущей позиции»
В то время как степпинг полезен для изучения каждой строки кода по отдельности, в большой программе перемещаться по коду с помощью этих команд не очень удобно. Но и здесь современные отладчики предлагают еще несколько инструментов для эффективной отладки программ.
Команда «Выполнить до текущей позиции» позволяет в одно нажатие выполнить весь код до строки, обозначенной курсором. Затем контроль обратно возвращается к нам, и мы можем проводить отладку с указанной точки уже более детально. Давайте попробуем, используя уже знакомую нам программу:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> 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;
. Затем выберите «Шаг с заходом» для старта сеанса отладки, а затем «Продолжить». Вы увидите, что вместо завершения выполнения программы и остановки сеанса отладки, отладчик остановится в указанной вами точке:
Точки останова чрезвычайно полезны, если вы хотите изучить только определенную часть кода. Просто задайте точку останова в выбранном участке кода, выберите команду «Продолжить» и отладчик автоматически остановится возле указанной строки. Затем вы сможете использовать команды степпинга для более детального просмотра/изучения кода.
В Студии же можно не только вперёд двигаться по коду , но и назад. Мышкой курсор отладчика сдвигать.
Помогите! я работаю в Dev C++ там отладчик вызывается по другому (а как? я не знаю) и он не работает только консоль появляется и все!
И почему во многих уроках вы практически не объясняете по Dev c++,
ну например урок #4 почему там есть все а Dec c++ нет?
А так все очень доступно и понятно объясняете в остальных уроках)
Еще раз поблагодарю. Классный материал и перевод! Тоже склоняюсь к тому что скорее всего куплю PDF — ваш труд более чем стоит этого.
Спасибо за отзыв, мне приятно 😉
Лютый респект Вам, Юрий! Изучаю кресты по вашим урокам, обязательно дойду до финала. (Задумался о покупке PDF версии)
Огроменное пожалуйста 🙂 Мне приятно!
Привет! Почему порой шаги с заходом и обходом не работают, а просто компилируется вся программа? Стоит режим debug
Хотелось бы узнать, как выполнить эти действия в других средах. У меня DEV C++ и там ничего подобного не наблюдаю.
P.S. VS у меня тоже есть, но не могу найти иконку к ней, приходится заходить через установщик, это очень долго. Поэтому использую DEV C++.
Буду очень признательна, если кто-то подскажет, как найти иконку VS, чтобы вынести её на рабочий стол.
1.В нижней левой части экрана жмёшь на иконку "ПУСК" (значок винды)
2.1.Если у тебя windows 10:
пишешь фразу "Vis" и выбираешь из того, что появится Visual Studio
2.2.Если у тебя не 10-ка:
Ищешь вкладку поиск и там пишешь фразу "Vis" и выбираешь из того, что появится Visual Studio
3.Когда запустишь VS, внизу на панели задач будет её иконка.
Кликаешь на эту иконку правой кнопкой мыши
Выбираешь пункт что-то типа "Закрепить на панели задач"
Возможно ли, и как осуществлять отладку dll-проектов?
Не плохо было бы добавит как подключать отладчик, у меня почему то не прописан был путь к нему Code:Blocks . Пришлось гуглить. В Setting-> debugger ->Default->Executable path… указать путь нужного нам отладчика лежит в папке компилятора CodeBlocks\MinGB\bin\gdb32.exe
Спасибо,я использую и VS и Code::Blocks для разных задач и дебаггера там серьёзно не хватало.
В Code::Blocks 20.04 (портативная с MinGW) отладчик прописан в настройках из коробки
Мне кажется, стоило показать пример на более масштабной программе, а то, я думаю, многим не понятно, как это может пригодиться.
Мне пригодилось. Там дальше будет урок по вложенным циклам. И у меня одно задание никак не хотело выполняться правильно, и я не мог понять в чём причина. Начал отладку, наг за шагом следил что и как происходит. Я выявил все причины, программа начала работать именно так, как я и задумывал. Уже третий раз прохожу курс, ибо жизненные обстоятельства то и дело принуждают его забросить… Но я его закончу!
Заканчиваешь?
Ни одного комментария. А тема в программировании самая важная.
Без отладчика — как без рук.
joxi.ru/zAN47oWUBwgkPm
Вот пример нашего отладчика. Вроде горячие клавиши совпадают
=))
Это 1С? Жестко 🙂