3.9 – Использование встроенного отладчика: стек вызовов

Добавлено 24 апреля 2021 в 17:37

Современные отладчики содержат еще одно окно отладочной информации, которое может быть очень полезно при отладке программы, и это окно стека вызовов.

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

Стек вызовов (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 Окно стека вызовов при первой остановке на строке 5
Рисунок 1 – Окно стека вызовов при первой остановке на строке 5

Обратите внимание, что номера ваших строк могут немного отличаться (на 1), и что вместо [Внешний код] (External Code) вы можете увидеть кучу других функций с безумными названиями. Эти различия несущественны.

Здесь важны две верхние строчки. Снизу вверх мы видим, что сначала была вызвана функция main, а затем следующей была вызвана функция a.

Строка 5 рядом с функцией a показывает нам, где находится текущая точка выполнения (которая соответствует маркеру выполнения в окне редактора кода). Строка 17 во второй строке указывает строку, в которую будет выполнен возврат, когда управление вернется к функции main.

Теперь выберите команду продолжить отладку, чтобы перейти к следующей точке останова, которая будет в строке 10. Стек вызовов должен обновиться, чтобы отразить новую ситуацию:

Рисунок 2 Окно стека вызовов при остановке на строке 10
Рисунок 2 – Окно стека вызовов при остановке на строке 10

Вы можете заметить, что теперь в верхней строке стека вызовов находится функция b, что отражает тот факт, что функция b – это функция, которая выполняется в данный момент. Обратите внимание, что функция a больше не представлена в стеке вызовов. Это связано с тем, что функция a была удалена из стека вызовов при возврате.

Еще раз выберите команду продолжить отладку, и мы снова попадем в точку останова в строке 5 (потому что функция b вызывает функцию a). Стек вызовов будет выглядеть так:

Рисунок 3 Окно стека вызовов при второй остановке на строке 5
Рисунок 3 – Окно стека вызовов при второй остановке на строке 5

Теперь в стеке вызовов три функции: (снизу вверх) main, которая вызвала функцию b, которая вызвала функцию a.

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

Заключение

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

Теги

C++ / CppCode::BlocksDebugIDELearnCppVisual StudioДля начинающихОбучениеОтладкаОтладчик / DebuggerПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.