27 }
28 DBUG_RETURN(0);
29 }
Эта программа иллюстрирует большинство важных моментов. Макрос DBUG_ENTER()
(строка 12) должен быть вызван после объявлений переменных и перед любым другим кодом. (Это потому, что он сам объявляет несколько частных переменных.[176])
Макрос DBUG_PROCESS()
(строка 13) устанавливает имя программы, главным образом, для использования в выводимых библиотекой сообщениях. Этот макрос должен вызываться лишь однажды, из main()
.
Макрос DBUG_PUSH_ENV()
(строка 14) заставляет библиотеку проверить указанную переменную окружения (в данном случае DBUG
) на предмет управляющей строки (Управляющие строки dbug
вскоре будут рассмотрены.) Библиотека может, сохранив свое текущее состояние и использовав новое, создавать стек сохраненных состояний. Таким образом, этот макрос помещает в стек сохраненных состояний полученное от данной переменной окружения состояние. В данном примере использован случай, когда макрос создает первоначальное состояние. Если такой переменной окружения нет, ничего не происходит. (В качестве отступления, DBUG
является довольно общей переменной, возможно, GAWK_DBUG
было бы лучше [для gawk
].)
Макрос DBUG_PUSH
(строка 18) передает значение управляющей строки, полученной из опции командной строки -#
. (Новый код должен использовать getopt()
или getopt_long()
вместо ручного анализа аргументов.) Таким образом обычно включается режим отладки, но использование переменной окружения предоставляет также дополнительную гибкость.
Макрос DBUG_PRINT()
(строка 23) осуществляет вывод. Второй аргумент использует методику, которую мы описали ранее (см. раздел 15.4.1.1 «Используйте отладочные макросы»), по включению в скобки всего списка аргументов printf()
, делая его простым аргументом, насколько это касается препроцессора С. Обратите внимание, что завершающий символ конца строки в форматирующей строке не указывается; библиотека dbug
вставляет его за вас.
При печати dbug
по умолчанию выводит все операторы DBUG_PRINT()
. Первый аргумент является строкой, которая может использоваться для ограничения вывода лишь теми макросами DBUG_PRINT()
, которые используют эту строку.
Наконец, макрос DBUG_RETURN()
(строка 28) используется вместо обычного оператора return
для возврата значения. Для использования с функциями void
имеется соответствующий макрос DBUG_VOID_RETURN
.
Оставшаяся часть программы заполнена функцией factorial()
:
1 #include <stdio.h>
2 #include "dbug.h"
3
4 int factorial (value)
5 register int value;
6 {
7 DBUG_ENTER("factorial");
8 DBUG_PRINT("find", ("find %d factorial", value));
9 if (value > 1) {
10 value *= factorial(value — 1);
11 }
12 DBUG_PRINT("result", ("result is %d", value));
13 DBUG_RETURN(value);
14 }
Когда программа откомпилирована и скомпонована вместе с библиотекой dbug
, ее можно запустить обычным способом. По умолчанию, программа не создает вывод отладки. Но со включенной отладкой доступны различные виды вывода:
$ factorial 1 2 3 /* Обычный запуск, без отладки */
1
2
6
$ factorial -#t 1 2 3/* Вывести трассировку вызовов функций, обратите внимание на вложенность */
| >factorial
| <factorial
1 /* Обычный вывод в stdout */
| >factorial
| | >factorial
| | <factorial /* Вывод отладки в stderr */
| <factorial
2
| >factorial
| | >factorial
| | | >factorial
| | | <factorial
| | <factorial
| <factorial
6
<?func?
$ factorial -#d 1 2/* Показать отладочные сообщения DBUG_PRINT() */
?func?: args: argv[2] = 1
factoriaclass="underline" find: find 1 factorial
factoriaclass="underline" result: result is 1
1
?func?: args: argv[3] = 2
factoriaclass="underline" find: find 2 factorial
factoriaclass="underline" find: find 1 factorial
factoriaclass="underline" result: result is 1
factoriaclass="underline" result: result is 2
2
Опция -#
управляет библиотекой dbug
. Она «особая» в том смысле, что DBUG_PUSH()
будет принимать всю строку, игнорируя ведущие символы '-#
', хотя вы могли бы использовать при желании другую опцию, передав DBUG_PUSH()
лишь строку аргументов опций (если вы используете getopt()
, это optarg
).
Управляющая строка состоит из набора опций и аргументов. Каждая группа опций и аргументов отделяется от других символом двоеточия. Каждая опция представлена одной буквой, а аргументы этой опции отделяются от нее запятыми. Например:
$ myprog -#d,mem,ipc:f,check_salary,check_start_date -f infile -o outfile
Опция d
включает вывод DBUG_PRINT()
, но лишь если первая строка аргумента является "mem
" или "ipc
". (Если аргументов нет, выводятся все сообщения DBUG_PRINT()
.) Сходным образом опция f
ограничивает трассировку вызовов функций лишь указанными функциями, check_salary()
и check_start_date()
.
Следующий список опций и аргументов воспроизведен из руководства библиотеки dbug
. Квадратные скобки заключают необязательные аргументы. Мы включаем здесь лишь те, которые находим полезными; полный список см. в документации.
d [,ключевые слова]
Разрешает вывод от макросов с указанными ключевыми словами. Пустой список ключевых слов предполагает, что выбраны все ключевые слова.
F
Помечает каждую строку вывода отладки именем исходного файла, содержащего макрос, осуществляющий вывод.
i
Идентифицирует процесс, выводящий каждую отладочную или трассировочную строку номером ID для этого процесса.
L
Помечает каждую строку вывода отладчика номером строки исходного файла, в котором находится осуществляющий вывод макрос.
о[,файл]
Перенаправляет поток вывода отладчика в указанный файл. Потоком вывода по умолчанию является stderr
. Пустой список аргументов перенаправляет вывод в stdout
.
t[,N]
Включает трассировку потока управления функций. Максимальная глубина вложения определяется N
, по умолчанию используется 200.
Для завершения нашего обсуждения вот остальные макросы, определенные библиотекой dbug
.
DBUG_EXECUTE(строка, код)
Этот макрос похож на DBUG_PRINT()
: первый аргумент является строкой, выбранной с помощью опции d
, а второй — код для исполнения:
DBUG_EXECUTE("abort", abort());
176
В C99, который допускает смешивание объявлений переменных с исполняемым кодом, это составляет меньшую проблему, но помните, что этот пакет был разработан для K&R С —