2010-03-11 7 views
4

Je me suis mis à créer une macro de débogage C soignée, pas vraiment sûr de ce que je voulais vraiment (et étant désemparé quand il s'agit de macros) je me suis tourné vers google. Quelque temps plus tard, je pense maintenant que je sais ce que je veux, mais pas comment cela fonctionne. Je n'ai pas eu beaucoup de chance d'obtenir des informations décentes sur les macros et les techniques de débogage.Macro de débogage C (avec différentes "sources" de débogage)

Ce que je l'ai utilisé dans le passé ont été quelque chose comme ceci:

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

Le problème est qu'il peut être assez désordonné et, finalement, vous finissez en commentant les anciens messages de débogage eventhough vous aurez probablement besoin d'eux plus tard.

Le meilleur exemple que j'ai trouvé de quelques diapositives à partir d'un cours avancé de c, qui se trouve ici: http://www.mpi-inf.mpg.de/departments/rg1/teaching/advancedc-ws08/script/lecture07.pdf (les parties pertinentes sont diapositive 19-23, mais la plupart sont inclus ci-dessous)

En tant que diapositives, ils ont malheureusement besoin d'explications. Mais ils mentionnent quelque chose qui semble très utile:

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

Où MOD_PARSER est un module debug/catégorie et le reste des arguments sont destinés à donner à printf.

Et la mise en œuvre de DBG:

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

Problème n ° 1 est d'écrire la fonction dbg_printer, je ne sais pas comment passer le nombre variable d'arguments à une instruction printf.

Les diapositives vont à discuter de la façon d'ajouter de nouveaux modules avec élégance et je suis assez certain que je ne l'ai pas compris du tout, mais quand même ...

*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, 
}; 

Je ne vois pas pourquoi vous gauche changer les valeurs des éléments d'énumération, de chouettes truc que je Je suis manquant? Mis à part les diapositives ci-dessus, je n'ai pas vu un seul exemple ou article/post/quoi que ce soit mentionnant même ce peut-être que ce n'est même pas adapté à mes fins. Cela semble-t-il raisonnable et des techniques similaires sont-elles réellement utilisées?

A partir de maintenant la question est de savoir comment mettre en œuvre dbg_printer et vraiment comment l'énumération des modules de débogage est censé fonctionner, mais en voyant que la façon dont je pourrais avoir tout incompris qui pourrait changer :(

Répondre

2

Pour passer le nombre variable de arguments de dbg_printer, vous appelez vfprintf au lieu de fprintf.Quelque chose comme ceci:

#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); 
    } 
} 

(Cet exemple montre comment permettre un ensemble de messages de débogage pour aller à stderr, et un autre ensemble dans un fichier de débogage)

La gauche décalage des constantes permet avoir un sous-ensemble de modules sélectionnés, pas seulement un seul. Par exemple, le code ci-dessus, vous activer le débogage de l'analyseur et solveur à stderr comme ceci:

dbg_mod_stderr |= MOD_PARSER; 
dbg_mod_stderr |= MOD_SOLVER; 

et vous pouvez mettre plus tard le débogage du solveur comme ceci:

dbg_mod_stderr &= ~MOD_SOLVER; 

(Cela fonctionne car chaque constante MOD_ n'a qu'un seul bit unique dans la représentation binaire).

+0

fprintf (dbg_fil e, fmt, ap); devrait être vfprintf ??? – Dipstick

+0

Oups! Maintenant corrigé – caf

6

Je ne vois pas pourquoi vous auriez décalé à gauche les valeurs des éléments d'énumération, un truc astucieux qui me manque?

Ceci est très probablement de sorte que plus d'un des éléments peut être indiqué en les joignant avec un bit ou un bit.

Mon préféré macro debug-vous connecter ne dispose pas du module spécificité, mais ajoute le nom et le numéro de ligne à la sortie et est relativement simple:

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

modifier: Ceci est plus comme ce que j'utilise de nos jours, en fonction des commentaires ci-dessous (et __PRETTY_FUNCTION__##__VA_ARGS__) et this 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 
+0

+1 pour c99 __FILE__ et __LINE__ - ne pas oublier __func__ –

+0

commentaires ont les caractères de soulignement dépouillés. Je crois que c'est

+1

Je fais semblable, mais avec certains compilateurs "__FILE__" est le nom de fichier complet, y compris le chemin, est donc souvent inutilisable sur les grands projets avec des arbres de code source compliqué. Au lieu de cela, je définis DBG_MODULE qui peut être un fichier ou un paquet et l'utilise avec "__func__". Si des macros de débogage doivent être laissées dans le code pour signaler des problèmes, alors le numéro de ligne n'est pas utile, car vous devriez extraire la version exacte du code utilisé (avec les mêmes macros de débogage dans !!!). En général, je trouve DBG_MODULE/"__ func__" beaucoup plus utile et utilisable que "__FILE __"/"__ LINE__". – Dipstick