gcc -Wall -pedantic -ansi
Они порождают много предупреждений и дополнительных проверок на соответствие стандартам языка С. Рекомендуем взять за правило использование этих опций, особенно Wall. Она генерирует полезную информацию при обнаружении ошибок в программе.
Чуть позже мы кратко обсудим и другие средства, lint и splint. Как и компилятор, они анализируют код и сообщают о фрагментах кода, которые могут быть некорректными.
Оснащение средствами контроля
Оснащение средствами контроля — это вставка в программу кода для сбора дополнительной информации о поведении программы во время ее выполнения. Очень популярна вставка вызовов функции printf для вывода значений переменных на разных стадиях выполнения программы. Вы можете с пользой для себя добавить несколько вызовов printf, но должны знать о том, что этот процесс повлечет за собой дополнительные редактирование и компиляцию при любом изменении программы и, конечно, вам придется удалить код, когда ошибки будут исправлены.
Здесь могут помочь два метода оснащения средствами контроля. Первый использует препроцессор языка С для выборочного включения кода средств контроля так, что вам нужно только перекомпилировать программу для вставки или удаления отладочного кода. Сделать это можно очень просто, с помощью конструкций, подобных приведенным далее:
#ifdef DEBUG
printf("variable x has value = %d\n", x);
#endif
Вы можете компилировать программу с флагом компилятора -DDEBUG для определения символического имени DEBUG и включения дополнительного кода и без этого флага — для удаления отладочного кода. Можно создать и более сложный вариант использования пронумерованных отладочных макросов:
#define BASIC_DEBUG 1
#define EXTRA_DEBUG 2
#define SUPER_DEBUG 4
#if (DEBUG & EXTRA_DEBUG)
printf...
#endif
В этом случае вы всегда должны определять макрос DEBUG, но можете настраивать объем отладочной информации или уровень детализации. Флаг компилятора -DDEBUG=5 в нашем примере активизирует макросы BASIC_DEBUG и SUPER_DEBUG, но не EXTRA_DEBUG. Флаг DDEBUG=0 отключит всю отладочную информацию. С другой стороны, вставка следующих строк устранит необходимость задания в командной строке DEBUG, если отладки не требуется.
#ifndef DEBUG
#define DEBUG 0
#endif
Несколько макросов, определенных препроцессором С, могут предоставить отладочную информацию. Эти макросы раскрываются для предоставления сведений о текущей компиляции (табл. 10.1).
Обратите внимание на то, что приведенные символические имена начинаются и заканчиваются двумя символами подчеркивания. Это стандартное правило для символических имен препроцессора, и вы должны аккуратно выбирать идентификаторы, чтобы избежать конфликтов. Термин "текущие" в предыдущих описаниях указывает на момент выполнения препроцессорной обработки, т.е. время и дата запуска компилятора и обработки файла.
Таблица 10.1
| Макрос | Описание |
|---|---|
__LINE__
|
Десятичная константа, предоставляющая номер текущей строки |
__FILE__
|
Строка, предоставляющая имя текущего файла |
__DATE__
|
Строка в форме "ммм дд гггг", текущая дата |
__TIME__
|
Строка в форме "чч:мм:сс", текущее время |
Выполните упражнение 10.1.
Далее приведена программа cinfo.c, которая выводит дату и время компиляции, если включен режим отладки.
#include <stdio.h>
# include <stdlib.h>
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 в командной строке, которая дает возможность пользователю включить отладку даже после того, как программа была введена в эксплуатацию, и включении функции мониторинга процесса отладки. Теперь можно вкраплять в код программы строки, подобные следующим: