Содержание
Отладка
Идея – программы часто не работают так, как того хочет программист. Какие ошибки сложнее всего искать?
- Runtime errors, приводящие к немедленной остановке программы. SEGFAULT, Double free corruption и т.п
- Логические ошибки, которые приводят к неверному поведению программы
Есть несколько техник, как искать подобные ошибки.
Способ 1. Отладочный вывод
Основные полезные моменты
- Все отладочные выводы следует делать в поток stderr
- При отладке полезно использовать макросы, сообщающие, например, номер строки и имя функции
- Полезно уметь «отключать» отладочные сообщения
Простой пример отладочных выводов «на коленке» (более подробно этот вопрос рассматривается в статье Logging with GCC):
#include <stdio.h> #define DEBUG int main(){ #ifdef DEBUG fprintf(stderr, "DEBUG: %s:%s:%d: %s\n", __FILE__, __func__, __LINE__, "Debug message"); #endif return 0; }
Почитать подробнее
Способ 2. gdb + cli
GDB имеет достаточно простой, но мощный командный интерфейс и хорошую справку по нему. Пример:
#include <stdio.h> #include <stdarg.h> void get_int(int* val) { val = NULL; printf("%d\n", *val); } int main() { printf("Hello!"); int* a; get_int(a); return 0; }
При запуске данной программы появляется ошибка segmentation fault, т.е попытка доступа к несуществующей/чужой памяти. Что можно сделать что её найти:
- Найти строчку, где происходит непосредственно обращение к невалидной памяти
- Изучить состояние переменных, памяти в тот момент, когда произошла ошибка
Для этого необходимо:
- Собрать программу с добавлением отладочных данных:
gcc -g myprog.c
- Открыть её в отладчике:
gdb ./a.out
- Запустить программу командой run:
(gdb) run
- Ввести исходные данные, если ваша программа получает какие-то данные на вход. Если требуется перенаправить на вход вашей программе содержимое файла, запустите ее с помощью
(gdb) run < input_file.txt
Вывод для программы после команды run будет следующий:
(gdb) run Starting program: /a.out Program received signal SIGSEGV, Segmentation fault. 0x0000555555555165 in get_int (val=0x0) at main.c:6 6 printf("%d\n", *val);
Теперь вы можете изучить состояние программы, например:
Написать
(gdb) where
и получить подробный стектрейс, чтобы узнать в каком файле и функции произошла ошибка:
(gdb) where #0 0x0000555555555165 in get_int (val=0x0) at main.c:6 #1 0x00005555555551ac in main () at main.c:13
Изучить состояние переменных с помощью команды «p <variable_name>»
(gdb) p val $1 = (int *) 0x0
Если вы хотите изучить состояние программы ДО того, как ошибка случится, то можете использовать команду «b» для расстановки точек останова. https://www.opennet.ru/docs/RUS/gdb/gdb_6.html
Полезные ссылки:
Способ 3. GDB + VSCode
WIP
Чтобы использовать отладчик gdb из IDE VSCode, необходимо:
Установить расширения для отладки и работы с языком С:
- Открыть ваш проект/файл в VSCode
- Расставить точки останова напротив интересующих вас строк кода (нажать слева от номер строки)
- Перейти в вкладку «Debug»
Нажать комбинацию клавиш ctrl+shift+P (откроется командная консоль vscode) и написать debug. Выбрать С/C++ debugging
Сохранить файл launch.json. Теперь у вас есть конфигурация для отладки этой программы. Запустите отладку, нажав F5
Теперь в VScode вам доступен интерфейс отладки:
- Справа панель управления отладкой
- Слева – состояние памяти и переменных
Архив
gdb + другие ide
Любая среда разработки или даже мощный текстовый редактор обычно предоставляют вам графический интерфейс для использования gdb при отладке своих программ. Обычно он достаточно наглядный и имеет хорошее описание для каждой IDE.
Вы можете самостоятельно найти описание использования отладчика в вашей любимой IDE. Для CLion можно посмотреть эти источники: