Чтение онлайн

на главную - закладки

Жанры

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

ЗАМЕЧАНИЕ. Идентификатор

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 = %d\n", myvar);

...

DPRINT2("v1 = %d, v2 = %f\n", v1, v2);

Имеется несколько макросов, по одному на каждый имеющийся аргумент, число которых определяете вы сами. Когда определен

MYAPPDEBUG
, вызовы макросов
DPRINTx
развертываются в вызовы
fprintf
. Когда
MYAPPDEBUG
не определен, эти вызовы развертываются в ничто. (Так, в сущности, работает
assert
; мы описали
assert
в разделе 12.1 «Операторы проверки:
assert
».)

Эта методика работает; мы сами ее использовали и видели, как ее рекомендуют в учебниках. Однако, она может быть усовершенствована и дальше с уменьшением количества макросов до одного:

/* МЕТОДИКА 2 --- наиболее переносима; рекомендуется */

/* В заголовочном файле приложения: */

#ifdef MYAPPDEBUG

#define DPRINT(stuff) fprintf stuff

#else

#define DPRINT(stuff)

#endif

/* В исходном файле приложения: */

DPRINT((stderr, "myvar = %d\n", myvar));

 /* Обратите внимание на двойные скобки */

Обратите внимание на то, как макрос извлекается с двумя наборами скобок! Поместив весь список аргументов для

fprintf
в один аргумент, вам больше не нужно определять произвольное число отладочных макросов.

Если вы используете компилятор, удовлетворяющий стандарту С 1999 г., у вас есть дополнительный выбор, который дает наиболее чистый отладочный код:

/* МЕТОДИКА 3 --- самая чистая, но только для C99 */

/* В заголовочном файле приложения: */

#ifdef MYAPPDEBUG

#define DPRINT(mesg, ...) fprintf(stderr, mesg, __VA_ARGS__)

#else

#define DPRINT(mesg, ...)

#endif

/* В исходном файле приложения: */

DPRINT("myvar = %d\n", myvar);

DPRINT("v1 = %d, v2 = %f\n", v1, v2);

Стандарт С 1999 г. предусматривает варьирующий макрос (variadic macros); т.е. макрос, который может принимать переменное число аргументов. (Это похоже на варьирующую функцию, наподобие

printf
). В макроопределении три точки '
...
' означают, что будет ноль или более аргументов. В теле макроса специальный идентификатор
__VA_ARGS__
замещается предусмотренными аргументами, сколько бы их ни было.

Преимуществом этого механизма является то, что при извлечении отладочного макроса необходим лишь один набор скобок, что делает чтение кода значительно более естественным. Это также сохраняет возможность использовать всего одно имя макроса вместо нескольких, которые меняются в соответствии с числом аргументов. Недостатком является то, что компиляторы C99 пока еще доступны не так широко, что снижает переносимость этой конструкции. (Однако, эта ситуация будет со временем улучшаться.)

Рекомендация: Текущие версии GCC поддерживают варьирующие макросы. Таким образом, если вы знаете, что никогда не будете использовать для компилирования своих программ что-то, кроме GCC (или какого-нибудь другого компилятора C99), можете использовать механизм C99. Однако, на момент написания, компиляторы C99 все еще не являются обычным явлением. Поэтому, если ваш код должен компилироваться разными компиляторами, следует использовать макрос в стиле с двумя парами скобок.

15.4.1.2. По возможности избегайте макросов с выражениями

В общем, макросы препроцессора С являются довольно острой палкой с двумя концами. Они предоставляют вам большую мощь, но также и большую возможность пораниться самому. [169]

Обычно для эффективности или ясности можно видеть такие макросы:

#define RS_is_null (RS_node->var_value == Nnull_string)

...

if (RS_is_null || today == TUESDAY) ...

169

Bjarne Stroustrup, создатель С++, настойчиво работал над тем, чтобы сделать использование препроцессора С совершенно ненужным в С++. По нашему мнению, он не вполне добился успеха:

#include
нужен до сих пор, но не обычные макросы. Для С препроцессор остается ценным и инструментом, но он должен использоваться благоразумно — Примеч. автора.

На первый взгляд, он выглядит замечательно. Условие '

RS_is_null
' ясно и просто для понимания и абстрагирует внутренние детали проверки. Проблема возникает, когда вы пытаетесь вывести значение в GDB:

(gdb) print RS_is_null

No symbol "RS_is_null" in current context.

В таком случае нужно разыскать определение макроса и вывести развернутое значение.

Рекомендация: Для представления важных условий в своей программе используйте переменные, значения которых при изменении условий явным образом меняется в коде.

Поделиться:
Популярные книги

Искушение генерала драконов

Лунёва Мария
2. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Искушение генерала драконов

Идеальный мир для Лекаря

Сапфир Олег
1. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря

Третье правило дворянина

Герда Александр
3. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Третье правило дворянина

Третий. Том 2

INDIGO
2. Отпуск
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 2

Лорд Системы 11

Токсик Саша
11. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 11

Обыкновенные ведьмы средней полосы

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Обыкновенные ведьмы средней полосы

Купеческая дочь замуж не желает

Шах Ольга
Фантастика:
фэнтези
6.89
рейтинг книги
Купеческая дочь замуж не желает

Para bellum

Ланцов Михаил Алексеевич
4. Фрунзе
Фантастика:
попаданцы
альтернативная история
6.60
рейтинг книги
Para bellum

Неверный

Тоцка Тала
Любовные романы:
современные любовные романы
5.50
рейтинг книги
Неверный

Неудержимый. Книга VI

Боярский Андрей
6. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга VI

Огненный князь

Машуков Тимур
1. Багряный восход
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Огненный князь

Вперед в прошлое 6

Ратманов Денис
6. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 6

Без шансов

Семенов Павел
2. Пробуждение Системы
Фантастика:
боевая фантастика
рпг
постапокалипсис
5.00
рейтинг книги
Без шансов

Истребители. Трилогия

Поселягин Владимир Геннадьевич
Фантастика:
альтернативная история
7.30
рейтинг книги
Истребители. Трилогия