Linux программирование в примерах - Роббинс Арнольд
Шрифт:
Интервал:
Закладка:
...
(gdb) <b>watch do_lint_old</b>
/* Установить отслеживаемую точку для переменной */
Hardware watchpoint 1: do_lint_old
(gdb) <b>run --lint-old 'BEGIN { print "hello, world" }'</b>
/* Запустить программу */
Starting program: /home/arnold/Gnu/gawk/gawk-3.1.4/gawk —lint-old
'BEGIN { print "hello, world" }'
Hardware watchpoint 1: do_lint_old
Hardware watchpoint 1: do_lint_old
Hardware watchpoint 1: do_lint_old
/* Проверка отслеживаемой точки при работе программы */
Hardware watchpoint 1: do_lint_old
Hardware watchpoint 1: do_lint_old
Old value = 0 /* Отслеживаемая точка останавливает программу */
New value = 1
0x420c4219 in _getopt_internal() from /lib/i686/libc.so.6
(gdb) <b>where</b> /* Трассировка стека */
#0 0x420c4219 in _getopt_internal() from /lib/i686/libc.so.6
#1 0x420c4e83 in getopt_long() from /lib/i686/libc.so.6
#2 0x080683a1 in main (argc=3, argv=0xbffff8a4) at main.c:293
#3 0x420158d4 in __libc_start_main() from /lib/i686/libc.so.6
(gdb) <b>quit</b> /* На данный момент мы закончили */
The program is running. Exit anyway? (y or n) <b>y</b> /* Да */
GDB может делать гораздо больше, чем мы здесь показали. Хотя руководство GDB большое, его стоит прочесть целиком хотя бы один раз, чтобы ознакомиться с его командами и возможностями. После этого, возможно, будет достаточно просмотреть файл NEWS в каждом новом дистрибутиве GDB, чтобы узнать, что нового или что изменилось.
Стоит также распечатать справочную карточку GDB, которая поставляется в дистрибутиве GDB в файле gdb/doc/refcard.tex. Создать печатную версию справочной карточки для PostScript после извлечения исходника и запуска configure можно с помощью следующих команд:
$ <b>cd gdb/doc</b> /* Перейти о подкаталог doc */
$ <b>make refcard.ps</b> /* Отформатировать справочную карточку */
Предполагается, что справочная карточка будет распечатана с двух сторон листа бумаги 8,5×11 дюймов[168] (размер «letter») в горизонтальном (landscape) формате. В ней на шести колонках предоставлена сводка наиболее полезных команд GDB. Мы рекомендуем распечатать ее и поместить под своей клавиатурой при работе с GDB.
15.4. Программирование для отладки
Имеется множество методик для упрощения отладки исходного кода, от простых до сложных. В данном разделе мы рассмотрим ряд из них.
15.4.1. Код отладки времени компилирования
Несколько методик относятся к самому исходному коду.
15.4.1.1. Использование отладочных макросов
Возможно, простейшей методикой времени компилирования является использование препроцессора для создания условно компилируемого кода. Например:
#ifdef DEBUG
fprintf(stderr, "myvar = %dn", myvar);
fflush(stderr);
#endif /* DEBUG */
Добавление -DDEBUG к командной строке компилятора вызывает fprintf() при выполнении программы.
Рекомендация: сообщения отладки посылайте в stderr, чтобы они не были потеряны в канале и чтобы их можно было перехватить при помощи перенаправления ввода/вывода. Убедитесь, что использовали fflush(), чтобы сообщения были выведены как можно скорее
ЗАМЕЧАНИЕ. Идентификатор DEBUG, хотя он и очевидный, также часто злоупотребляется. Лучшей мыслью является использование специфического для вашей программы идентификатора, такого как MYAPPDEBUG. Можно даже использовать различные идентификаторы для отладки кода в различных частях программы, таких, как файловый ввод/вывод, верификация данных, управление памятью и т.д.
Разбрасывание больших количеств операторов #ifdef по всему коду быстро становится утомительным. Большое количество #ifdef скрывают также логику программы. Должен быть лучший способ, и в самом деле, часто используется методика с условным определением специального макроса для вывода:
/* МЕТОДИКА 1 --- обычно используемая, но не рекомендуемая, см. текст */
/* В заголовочном файле приложения: */ #ifdef MYAPPDEBUG
#define DPRINT0(msg) fprintf(stderr, msg)
#define DPRINT1(msg, v1) fprintf(stderr, msg, v1)
#define DPRINT2(msg, v1, v2) fprintf(stderr, msg, v1, v2)
#define DPRINT3(msg, v1, v2, v3) fprintf(stderr, msg, v1, v2, v3)
#else /* ! MYAPPDEBUG */
#define DPRINT0(msg)
#define DPRINT1(msg, v1)
#define DPRINT2(msg, v1, v2)
#define DPRINT3(msg, v1, v2, v3)
#endif /* ! MYAPPDEBUG */
/* В исходном файле приложения: */
DPRINT1("myvar = %dn", myvar);
...
DPRINT2("v1 = %d, v2 = %fn", v1, v2);
Имеется несколько макросов, по одному на каждый имеющийся аргумент, число которых определяете вы сами. Когда определен MYAPPDEBUG, вызовы макросов DPRINT<i>x</i>() развертываются в вызовы fprintf(). Когда MYAPPDEBUG не определен, эти вызовы развертываются в ничто. (Так, в сущности, работает assert(); мы описали assert() в разделе 12.1 «Операторы проверки: assert()».)