C отладочный макрос (с разными «исходниками» отладки) - PullRequest
4 голосов
/ 12 марта 2010

Я намеревался получить аккуратный макрос для отладки C, не совсем уверенный в том, чего я действительно хотел (и не имея представления о макросах), я обратился к Google. Некоторое время спустя, и теперь я думаю, что знаю, чего хочу, но не как это работает. Мне не очень повезло с получением достойной информации о макросах и методах отладки.

То, что я использовал в прошлом, было примерно таким:

#ifdef DEBUG
 #define DBG(x) printf x
#else
 #define DBG(x) /* nothing */
#endif

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

Лучший пример, который я нашел, был из некоторых слайдов из продвинутого курса c, который можно найти здесь: http://www.mpi -inf.mpg.de / отделы / RG1 / обучение / advancedc-WS08 / скрипт / lecture07.pdf (соответствующие части - слайд 19-23, но большая часть приведена ниже)

Будучи слайдами лекций, они, к сожалению, нуждаются в объяснении, чтобы пойти. Но они упоминают кое-что, что кажется весьма полезным:

DBG((MOD_PARSER , "z = %d\n", z));

Где MOD_PARSER - это модуль / категория отладки, а остальные аргументы предназначены для printf.

И реализация DBG:

#ifdef PRGDEBUG
 #define DBG(x) dbg_printer x
#else
 #define DBG(x) /* nothing */
#endif
void dbg_printer(int module , const char *fmt, ...);

Проблема № 1 заключается в написании функции dbg_printer, я не уверен, как передать переменное число аргументов в оператор printf.

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

*How to add new modules elegantly
*Add a file debug_modules.def 
ADD_MOD(0, PARSER) 
ADD_MOD(1, SOLVER) 
ADD_MOD(2, PRINTER)

...

*“Generate” an enum with debug modules: debug.h
...
#define ADD_MOD(num, id) MOD_ ## id = 1 << num,
enum _debug_modules_t {
#include "debug_modules.def"
};
#undef ADD_MOD
...

...

*Preprocessor yields enum _debug_modules_t {
 MOD_PARSER = 1 << 0,
 MOD_SOLVER = 1 << 1,
 MOD_PRINTER = 1 << 2,
};

Не понимаю, почему вы бы сдвинули значения элементов перечисления влево, какой-нибудь изящный трюк, который мне не хватает?

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

На данный момент вопрос заключается в том, как реализовать dbg_printer и действительно, как должно работать перечисление отладочных модулей, но, видя, как я мог неправильно понять все, что может измениться: (

Ответы [ 2 ]

6 голосов
/ 12 марта 2010

Я не понимаю, почему вы бы сдвинули значения элементов перечисления влево, какой-нибудь изящный трюк, который мне не хватает?

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

Мой предпочитаемый макрос ведения журнала отладки не имеет специфичности для модуля, но добавляет имя файла и номер строки к выводу и относительно прост:

    #ifdef DEBUG
        #define DLOG(fmt, args...) printf("%s:%d "fmt,__FILE__,__LINE__,args)
    #else
        #define DLOG(fmt, args...)
    #endif

edit: Это больше похоже на то, что я использую в настоящее время, основываясь на комментариях ниже (__PRETTY_FUNCTION__ и ##__VA_ARGS__) и это Q & A (do {} while (0)):

    #ifdef DEBUG
        #define DLOG(fmt, ...) printf("%s:%d "fmt, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
    #else
        #define DLOG(fmt, ...) do {} while (0)
    #endif
2 голосов
/ 12 марта 2010

Чтобы передать переменное число аргументов из dbg_printer, вы вызываете vfprintf вместо fprintf. Примерно так:

#include <stdarg.h>

extern int dbg_mod_stderr;
extern int dbg_mod_file;
extern FILE *dbg_file;

void dbg_printer(int module , const char *fmt, ...)
{
    if (dbg_mod_stderr & module)
    {
        va_list ap;

        va_start(ap, fmt);
        vfprintf(stderr, fmt, ap);
        va_end(ap);
    }

    if (dbg_file != NULL && (dbg_mod_file & module))
    {
        va_list ap;

        va_start(ap, fmt);
        vfprintf(dbg_file, fmt, ap);
        va_end(ap);
    }
}

(В этом примере показано, как разрешить одному набору отладочных сообщений перейти на stderr, а другому набору отладочного файла)

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

dbg_mod_stderr |= MOD_PARSER;
dbg_mod_stderr |= MOD_SOLVER;

и позже вы можете отключить отладку решателя следующим образом:

dbg_mod_stderr &= ~MOD_SOLVER;

(Это работает, потому что каждая константа MOD_ имеет только один уникальный бит, установленный в двоичном представлении).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...