3.9 – Использование встроенного отладчика: стек вызовов
Современные отладчики содержат еще одно окно отладочной информации, которое может быть очень полезно при отладке программы, и это окно стека вызовов.
Когда ваша программа вызывает функцию, вы уже знаете, что она создает закладку для текущего местоположения, выполняет вызов функции и затем возвращается из нее. Как она узнает, куда вернуться? Ответ в том, что она отслеживает это в стеке вызовов.
Стек вызовов (call stack) – это список всех активных функций, которые были вызваны для перехода к текущей точке выполнения. Стек вызовов включает в себя запись для каждой вызываемой функции, а также строку кода, в которую будет выполнен возврат при возврате из функции. Всякий раз, когда вызывается новая функция, эта функция добавляется в верхнюю часть стека вызовов. Когда происходит возврат из текущей функции в вызывающую, эта функция удаляется из вершины стека вызовов, и управление возвращается функции, находящейся чуть ниже нее.
Окно стека вызовов – это окно отладчика, которое показывает текущий стек вызовов. Если вы не видите окно стека вызовов, вам нужно будет указать среде IDE, чтобы она его показала.
Для пользователей Visual Studio
В Visual Studio окно стека вызовов можно найти в меню Отладка (Debug) → Окна (Windows) → Стек вызовов (Call Stack). Обратите внимание, что вы должны находиться в сеансе отладки, чтобы активировать это окно.
Для пользователей Code::Blocks
В Code::Blocks окно стека вызовов можно найти через меню Debug (Отладка) → Debugging windows (Окна отладки) → Call Stack (Стек вызовов).
Давайте посмотрим на стек вызовов на примере программы:
#include <iostream>
void a()
{
std::cout << "a() called\n";
}
void b()
{
std::cout << "b() called\n";
a();
}
int main()
{
a();
b();
return 0;
}
Поместите точки останова в строки 5 и 10 этой программы, а затем запустите режим отладки. Поскольку функция a
вызывается первой, точка останова в строке 5 будет достигнута первой.
На этом этапе вы должны увидеть что-то вроде этого:
Обратите внимание, что номера ваших строк могут немного отличаться (на 1), и что вместо [Внешний код] (External Code) вы можете увидеть кучу других функций с безумными названиями. Эти различия несущественны.
Здесь важны две верхние строчки. Снизу вверх мы видим, что сначала была вызвана функция main
, а затем следующей была вызвана функция a
.
Строка 5 рядом с функцией a
показывает нам, где находится текущая точка выполнения (которая соответствует маркеру выполнения в окне редактора кода). Строка 17 во второй строке указывает строку, в которую будет выполнен возврат, когда управление вернется к функции main
.
Теперь выберите команду продолжить отладку, чтобы перейти к следующей точке останова, которая будет в строке 10. Стек вызовов должен обновиться, чтобы отразить новую ситуацию:
Вы можете заметить, что теперь в верхней строке стека вызовов находится функция b
, что отражает тот факт, что функция b
– это функция, которая выполняется в данный момент. Обратите внимание, что функция a
больше не представлена в стеке вызовов. Это связано с тем, что функция a
была удалена из стека вызовов при возврате.
Еще раз выберите команду продолжить отладку, и мы снова попадем в точку останова в строке 5 (потому что функция b
вызывает функцию a
). Стек вызовов будет выглядеть так:
Теперь в стеке вызовов три функции: (снизу вверх) main
, которая вызвала функцию b
, которая вызвала функцию a
.
Стек вызовов полезен в сочетании с точками останова, когда достигается точка останова, и вы хотите знать, какие функции были вызваны для перехода к этой конкретной точке кода.
Заключение
Поздравляем, теперь вы знаете основы использования встроенного отладчика! Используя пошаговое выполнение, точки останова, отслеживание переменных и окно стека вызовов, у вас есть основы для отладки практически любой проблемы. Как и во многих других вещах, для того, чтобы научиться пользоваться отладчиком, требуется определенная практика и метод проб и ошибок. Но опять же, мы повторим, что время, потраченное на изучение того, как эффективно использовать встроенный отладчик, окупится многократно за счет экономии времени на отладку ваших программ!