В этом случае вы всегда должны определять макрос DEBUG
-DDEBUG=5 в нашем примере активизирует макросы BASIC_DEBUG и SUPER_DEBUG, но не EXTRA_DEBUG. Флаг DDEBUG=0 отключит всю отладочную информацию. С другой стороны, вставка следующих строк устранит необходимость задания в командной строке DEBUG, если отладки не требуется.#ifndef DEBUG
#define DEBUG 0
#endif
Несколько макросов, определенных препроцессором С, могут предоставить отладочную информацию. Эти макросы раскрываются для предоставления сведений о текущей компиляции (табл. 10.1).
Обратите внимание на то, что приведенные символические имена начинаются и заканчиваются двумя символами подчеркивания. Это стандартное правило для символических имен препроцессора, и вы должны аккуратно выбирать идентификаторы, чтобы избежать конфликтов. Термин "текущие" в предыдущих описаниях указывает на момент выполнения препроцессорной обработки, т.е. время и дата запуска компилятора и обработки файла.
| Макрос | Описание |
|---|---|
__LINE__ | Десятичная константа, предоставляющая номер текущей строки |
__FILE__ | Строка, предоставляющая имя текущего файла |
__DATE__ | Строка в форме "ммм дд гггг", текущая дата |
__TIME__ | Строка в форме "чч:мм:сс", текущее время |
Выполните упражнение 10.1.
Далее приведена программа cinfo.c, которая выводит дату и время компиляции, если включен режим отладки.
#include
# include
int main() {
#ifdef DEBUG
printf("Compiled: " __DATE__ " at " __TIME__ "\n");
printf("This is line %d of file %s\n", __LINE__, __FILE__);
#endif
printf("hello world\n");
exit(0);
}
Когда вы откомпилируете эту программу с включенным режимом отладки (используя флаг -DDEBUG
$ cc -о cinfo -DDEBUG cinfo.c
$ ./cinfo
Compiled: Jun 30 2007 at 22:58:43
This is line 8 of file cinfo.c
hello world
$
Как это работает
Препроцессор С, часть компилятора, отслеживает текущую строку и текущий файл во время компиляции. Он подставляет текущие (времени компиляции) значения этих переменных везде, где обнаруживает символические имена __LINE__
__FILE__. Дата и время компиляции становятся доступными аналогичным образом.Поскольку __DATE__
__TIME__ — строки, вы можете объединить их в функции printf с помощью строк формата, т.к. в языке С ANSI смежные строки воспринимаются как одна.Прежде чем двигаться дальше, стоит отметить, что существует способ применения функции printf
#ifdef DEBUG, требующего перекомпиляции программы перед ее использованием.Метод заключается во вставке глобальной переменной как флага отладки, разрешении опции -d
if (debug) {
sprintf(msg, ...)
write_debug(msg)
}
Записывать вывод отладки следует в стандартный поток ошибок stderr
syslog.Если вы вставляете в программу подобную трассировку для решения проблем, возникающих на этапе разработки, просто оставьте этот код в программе. Если вы будете чуть внимательнее, чем всегда, такой подход не вызовет никаких проблем. Выигрыш проявится, когда программа будет введена в эксплуатацию; если пользователи обнаружат проблему, они смогут выполнить программу в режиме отладки и диагностировать ошибки для вас. Вместо известия о том, что программа выдает сообщение о нарушении сегментации, они смогут написать, что конкретно делает программа в ходе выполнения, а не только описать свои действия. Разница может оказаться огромной.
У этого метода есть явный недостаток: программа становится больше, чем должна быть. В большинстве случаев это, скорее, мнимая проблема, чем реальная. Программа может стать на 20–30% больше, но чаще всего это не оказывает никакого существенного влияния на ее производительность. Снижение производительности наступает при увеличении размера на несколько порядков, а не на небольшую величину.