Mon probleme est donc comment ecrire une MACRO qui puisse
avoir une impacte nulle pour du code en "release" ! Bien sur le NOP
Logger
est deja assez leger... Mais bon il y a surement moyens de faire mieux
non ?
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Aurelien Regat-Barrel
Mon probleme est donc comment ecrire une MACRO qui puisse avoir une impacte nulle pour du code en "release" ! Bien sur le NOP Logger est deja assez leger... Mais bon il y a surement moyens de faire mieux non ?
C'est le nombre variable d'argument qui te pose problème si j'ai bien compris. Y'a des compilos qui permettent de faire de telles macros, mais c'est pas standard. Tu peux parenthéser l'appel à LOGGER:
#define LOGGER(x) printf x
LOGGER( ("hello %s", "world!" ) );
ou bricoler un truc à base de if(0) peut être...
#define LOGGER if ( 0 ) noplog
enfin, plutôt:
#define LOGGER if ( 1 ) {} else noplog
d'après mes souvenirs sur la bonne manière d'écrire des macros.
-- Aurélien Regat-Barrel
Mon probleme est donc comment ecrire une MACRO qui puisse
avoir une impacte nulle pour du code en "release" ! Bien sur le NOP
Logger
est deja assez leger... Mais bon il y a surement moyens de faire mieux
non ?
C'est le nombre variable d'argument qui te pose problème si j'ai bien
compris. Y'a des compilos qui permettent de faire de telles macros, mais
c'est pas standard. Tu peux parenthéser l'appel à LOGGER:
#define LOGGER(x) printf x
LOGGER( ("hello %s", "world!" ) );
ou bricoler un truc à base de if(0) peut être...
#define LOGGER if ( 0 ) noplog
enfin, plutôt:
#define LOGGER if ( 1 ) {} else noplog
d'après mes souvenirs sur la bonne manière d'écrire des macros.
Mon probleme est donc comment ecrire une MACRO qui puisse avoir une impacte nulle pour du code en "release" ! Bien sur le NOP Logger est deja assez leger... Mais bon il y a surement moyens de faire mieux non ?
C'est le nombre variable d'argument qui te pose problème si j'ai bien compris. Y'a des compilos qui permettent de faire de telles macros, mais c'est pas standard. Tu peux parenthéser l'appel à LOGGER:
#define LOGGER(x) printf x
LOGGER( ("hello %s", "world!" ) );
ou bricoler un truc à base de if(0) peut être...
#define LOGGER if ( 0 ) noplog
enfin, plutôt:
#define LOGGER if ( 1 ) {} else noplog
d'après mes souvenirs sur la bonne manière d'écrire des macros.
-- Aurélien Regat-Barrel
Patrick 'Zener' Brunet
Bonjour.
Je réponds à mderie
En deux mots, j'ai un tout petit bout de code pour sortir des traces via le port reseau (voici la seule fonction a utilisee :) :
LOGGER etant un simple alias pour ne pas specifier le type de "transport" pour les logs.
J'ai eu le problème dans une telle application. A priori les macros à liste variable ça n'existe pas, sauf effets de bords bizarres.
J'ai donc procédé ainsi:
#define COMMA ,
LOGGER( "Une %s à %u euros", "astuce" COMMA 2);
Ca ne couvre qu'un niveau d'imbrication bien sûr.
Cordialement,
-- /*************************************** * Patrick BRUNET * E-mail: lien sur http://zener131.free.fr/ContactMe ***************************************/
kanze
Aurelien Regat-Barrel wrote:
Mon probleme est donc comment ecrire une MACRO qui puisse avoir une impacte nulle pour du code en "release" ! Bien sur le NOP Logger est deja assez leger... Mais bon il y a surement moyens de faire mieux non ?
C'est le nombre variable d'argument qui te pose problème si j'ai bien compris. Y'a des compilos qui permettent de faire de telles macros, mais c'est pas standard.
Ça dépend. Il faut d'abord savoir s'il fait du C ou du C++. Les macros variadiques existent bien en C, voir __VA_ARGS__. Et en C++, il n'y a aucun problème à écrire quelque chose du genre :
LOGGER( "x = " << x ) ;
avec : #define LOGGER( msg ) log << msg ou : #define LOGGER( msg )
Tu peux parenthéser l'appel à LOGGER:
#define LOGGER(x) printf x
LOGGER( ("hello %s", "world!" ) );
ou bricoler un truc à base de if(0) peut être...
#define LOGGER if ( 0 ) noplog
enfin, plutôt:
#define LOGGER if ( 1 ) {} else noplog
d'après mes souvenirs sur la bonne manière d'écrire des macros.
En effet, Loïc a proposé quelque chose de ce genre dernièrement. On a soit : #define LOGGER getlog( __FILE__, __LINE__ ) soit #define LOGGER if ( true ) ; else dummy (Note bien que dans ce cas-ci, même avec les logs désactivés lors de la compilation, il faut bien que ton programme contient un object dummy.)
Ici aussi, on écrit ensuite : LOGGER << "x = " << x ;
(Au fond, je me démande si: #define LOGGER false && dummy ne serait pas mieux pour supprimer le log. Ça permettrait d'introduire des logs dans un initialisateur dans un constructeur, par exemple : Toto::Toto( int titi ) : myTiti( ((LOGGER << "titi = " << titi), titi) ) // ... .)
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aurelien Regat-Barrel wrote:
Mon probleme est donc comment ecrire une MACRO qui puisse
avoir une impacte nulle pour du code en "release" ! Bien sur
le NOP Logger est deja assez leger... Mais bon il y a
surement moyens de faire mieux non ?
C'est le nombre variable d'argument qui te pose problème si
j'ai bien compris. Y'a des compilos qui permettent de faire de
telles macros, mais c'est pas standard.
Ça dépend. Il faut d'abord savoir s'il fait du C ou du C++. Les
macros variadiques existent bien en C, voir __VA_ARGS__. Et en
C++, il n'y a aucun problème à écrire quelque chose du genre :
LOGGER( "x = " << x ) ;
avec :
#define LOGGER( msg ) log << msg
ou :
#define LOGGER( msg )
Tu peux parenthéser l'appel à LOGGER:
#define LOGGER(x) printf x
LOGGER( ("hello %s", "world!" ) );
ou bricoler un truc à base de if(0) peut être...
#define LOGGER if ( 0 ) noplog
enfin, plutôt:
#define LOGGER if ( 1 ) {} else noplog
d'après mes souvenirs sur la bonne manière d'écrire des macros.
En effet, Loïc a proposé quelque chose de ce genre dernièrement.
On a soit :
#define LOGGER getlog( __FILE__, __LINE__ )
soit
#define LOGGER if ( true ) ; else dummy
(Note bien que dans ce cas-ci, même avec les logs désactivés
lors de la compilation, il faut bien que ton programme contient
un object dummy.)
Ici aussi, on écrit ensuite :
LOGGER << "x = " << x ;
(Au fond, je me démande si:
#define LOGGER false && dummy
ne serait pas mieux pour supprimer le log. Ça permettrait
d'introduire des logs dans un initialisateur dans un
constructeur, par exemple :
Toto::Toto(
int titi )
: myTiti( ((LOGGER << "titi = " << titi), titi) )
// ...
.)
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Mon probleme est donc comment ecrire une MACRO qui puisse avoir une impacte nulle pour du code en "release" ! Bien sur le NOP Logger est deja assez leger... Mais bon il y a surement moyens de faire mieux non ?
C'est le nombre variable d'argument qui te pose problème si j'ai bien compris. Y'a des compilos qui permettent de faire de telles macros, mais c'est pas standard.
Ça dépend. Il faut d'abord savoir s'il fait du C ou du C++. Les macros variadiques existent bien en C, voir __VA_ARGS__. Et en C++, il n'y a aucun problème à écrire quelque chose du genre :
LOGGER( "x = " << x ) ;
avec : #define LOGGER( msg ) log << msg ou : #define LOGGER( msg )
Tu peux parenthéser l'appel à LOGGER:
#define LOGGER(x) printf x
LOGGER( ("hello %s", "world!" ) );
ou bricoler un truc à base de if(0) peut être...
#define LOGGER if ( 0 ) noplog
enfin, plutôt:
#define LOGGER if ( 1 ) {} else noplog
d'après mes souvenirs sur la bonne manière d'écrire des macros.
En effet, Loïc a proposé quelque chose de ce genre dernièrement. On a soit : #define LOGGER getlog( __FILE__, __LINE__ ) soit #define LOGGER if ( true ) ; else dummy (Note bien que dans ce cas-ci, même avec les logs désactivés lors de la compilation, il faut bien que ton programme contient un object dummy.)
Ici aussi, on écrit ensuite : LOGGER << "x = " << x ;
(Au fond, je me démande si: #define LOGGER false && dummy ne serait pas mieux pour supprimer le log. Ça permettrait d'introduire des logs dans un initialisateur dans un constructeur, par exemple : Toto::Toto( int titi ) : myTiti( ((LOGGER << "titi = " << titi), titi) ) // ... .)
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aurelien Regat-Barrel
En effet, Loïc a proposé quelque chose de ce genre dernièrement. On a soit : #define LOGGER getlog( __FILE__, __LINE__ ) soit #define LOGGER if ( true ) ; else dummy (Note bien que dans ce cas-ci, même avec les logs désactivés lors de la compilation, il faut bien que ton programme contient un object dummy.)
C'est à peu près ce que j'ai dans mon appli, sauf que getlog() renvoie un stream qui wrapp std::cout/ofstream/... ou qui ne fait rien du tout. J'ai pas cherché à évaluer si le compilateur supprimait son utilisation, vu que jusque là je n'en n'ai pas éprouvé le besoin.
Ici aussi, on écrit ensuite : LOGGER << "x = " << x ;
(Au fond, je me démande si: #define LOGGER false && dummy ne serait pas mieux pour supprimer le log. Ça permettrait d'introduire des logs dans un initialisateur dans un constructeur, par exemple : Toto::Toto( int titi ) : myTiti( ((LOGGER << "titi = " << titi), titi) ) // ... ..)
Actuellement, dans mon cas, les logs sont supprimés en recompilant (uniquement) getlog.cpp pour que getlog() renvoie un wrapper "nul". Je réalise qu'on pourrait aisément avoir la même chose avec un :
#define LOGGER if ( !log_are_enabled ) ; else dummy
et ainsi avoir un comportement dynamique, pour le coût d'un if(). Je ne sais pas vraiment pourquoi, mais utiliser
#define LOGGER log_are_enabled && dummy
me parrait plus risqué.
-- Aurélien Regat-Barrel
En effet, Loïc a proposé quelque chose de ce genre dernièrement.
On a soit :
#define LOGGER getlog( __FILE__, __LINE__ )
soit
#define LOGGER if ( true ) ; else dummy
(Note bien que dans ce cas-ci, même avec les logs désactivés
lors de la compilation, il faut bien que ton programme contient
un object dummy.)
C'est à peu près ce que j'ai dans mon appli, sauf que getlog() renvoie
un stream qui wrapp std::cout/ofstream/... ou qui ne fait rien du tout.
J'ai pas cherché à évaluer si le compilateur supprimait son utilisation,
vu que jusque là je n'en n'ai pas éprouvé le besoin.
Ici aussi, on écrit ensuite :
LOGGER << "x = " << x ;
(Au fond, je me démande si:
#define LOGGER false && dummy
ne serait pas mieux pour supprimer le log. Ça permettrait
d'introduire des logs dans un initialisateur dans un
constructeur, par exemple :
Toto::Toto(
int titi )
: myTiti( ((LOGGER << "titi = " << titi), titi) )
// ...
..)
Actuellement, dans mon cas, les logs sont supprimés en recompilant
(uniquement) getlog.cpp pour que getlog() renvoie un wrapper "nul". Je
réalise qu'on pourrait aisément avoir la même chose avec un :
#define LOGGER if ( !log_are_enabled ) ; else dummy
et ainsi avoir un comportement dynamique, pour le coût d'un if(). Je ne
sais pas vraiment pourquoi, mais utiliser
En effet, Loïc a proposé quelque chose de ce genre dernièrement. On a soit : #define LOGGER getlog( __FILE__, __LINE__ ) soit #define LOGGER if ( true ) ; else dummy (Note bien que dans ce cas-ci, même avec les logs désactivés lors de la compilation, il faut bien que ton programme contient un object dummy.)
C'est à peu près ce que j'ai dans mon appli, sauf que getlog() renvoie un stream qui wrapp std::cout/ofstream/... ou qui ne fait rien du tout. J'ai pas cherché à évaluer si le compilateur supprimait son utilisation, vu que jusque là je n'en n'ai pas éprouvé le besoin.
Ici aussi, on écrit ensuite : LOGGER << "x = " << x ;
(Au fond, je me démande si: #define LOGGER false && dummy ne serait pas mieux pour supprimer le log. Ça permettrait d'introduire des logs dans un initialisateur dans un constructeur, par exemple : Toto::Toto( int titi ) : myTiti( ((LOGGER << "titi = " << titi), titi) ) // ... ..)
Actuellement, dans mon cas, les logs sont supprimés en recompilant (uniquement) getlog.cpp pour que getlog() renvoie un wrapper "nul". Je réalise qu'on pourrait aisément avoir la même chose avec un :
#define LOGGER if ( !log_are_enabled ) ; else dummy
et ainsi avoir un comportement dynamique, pour le coût d'un if(). Je ne sais pas vraiment pourquoi, mais utiliser
#define LOGGER log_are_enabled && dummy
me parrait plus risqué.
-- Aurélien Regat-Barrel
kanze
Aurelien Regat-Barrel wrote:
En effet, Loïc a proposé quelque chose de ce genre dernièrement. On a soit : #define LOGGER getlog( __FILE__, __LINE__ ) soit #define LOGGER if ( true ) ; else dummy (Note bien que dans ce cas-ci, même avec les logs désactivés lors de la compilation, il faut bien que ton programme contient un object dummy.)
C'est à peu près ce que j'ai dans mon appli, sauf que getlog() renvoie un stream qui wrapp std::cout/ofstream/... ou qui ne fait rien du tout. J'ai pas cherché à évaluer si le compilateur supprimait son utilisation, vu que jusque là je n'en n'ai pas éprouvé le besoin.
Tout à fait. Je n'ai jamais eu besoin de supprimer la configuration dynamique du log non plus -- correctement écrit et utilisé, les tests consument vraiment peu de temps. Mais la possibilité de pouvoir le faire a souvent été essentiel pour faire accepter politiquement le logging.
Ici aussi, on écrit ensuite : LOGGER << "x = " << x ;
(Au fond, je me démande si: #define LOGGER false && dummy ne serait pas mieux pour supprimer le log. Ça permettrait d'introduire des logs dans un initialisateur dans un constructeur, par exemple : Toto::Toto( int titi ) : myTiti( ((LOGGER << "titi = " << titi), titi) ) // ... ..)
Actuellement, dans mon cas, les logs sont supprimés en recompilant (uniquement) getlog.cpp pour que getlog() renvoie un wrapper "nul". Je réalise qu'on pourrait aisément avoir la même chose avec un :
#define LOGGER if ( !log_are_enabled ) ; else dummy
et ainsi avoir un comportement dynamique, pour le coût d'un if(). Je ne sais pas vraiment pourquoi, mais utiliser
#define LOGGER log_are_enabled && dummy
me parrait plus risqué.
C'est cependant plus ou moins ce qui se trouve dans la plupart des macros pour assert. L'intérêt, comme j'ai dit, c'est que c'est une expression, et qu'il peut servir (avec l'opérateur virgule) dans des contextes où seulement une expression est permise. La risque, évidemment, c'est aussi que c'est une expression, ce qui donne davantage de possibilités à le faire foirer : true || LOGGER << ..., par exemple,
Dans la pratique, je ne travaille pas avec des programmeurs qui cherchent à détourner ce que j'ai fait à ce point-là, et je n'ai pas vu des « accidents » avec l'expression qui n'ont pas provoqué des erreurs de compilation.
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aurelien Regat-Barrel wrote:
En effet, Loïc a proposé quelque chose de ce genre dernièrement.
On a soit :
#define LOGGER getlog( __FILE__, __LINE__ )
soit
#define LOGGER if ( true ) ; else dummy
(Note bien que dans ce cas-ci, même avec les logs désactivés
lors de la compilation, il faut bien que ton programme contient
un object dummy.)
C'est à peu près ce que j'ai dans mon appli, sauf que getlog()
renvoie un stream qui wrapp std::cout/ofstream/... ou qui ne
fait rien du tout. J'ai pas cherché à évaluer si le
compilateur supprimait son utilisation, vu que jusque là je
n'en n'ai pas éprouvé le besoin.
Tout à fait. Je n'ai jamais eu besoin de supprimer la
configuration dynamique du log non plus -- correctement écrit et
utilisé, les tests consument vraiment peu de temps. Mais la
possibilité de pouvoir le faire a souvent été essentiel pour
faire accepter politiquement le logging.
Ici aussi, on écrit ensuite :
LOGGER << "x = " << x ;
(Au fond, je me démande si:
#define LOGGER false && dummy
ne serait pas mieux pour supprimer le log. Ça permettrait
d'introduire des logs dans un initialisateur dans un
constructeur, par exemple :
Toto::Toto(
int titi )
: myTiti( ((LOGGER << "titi = " << titi), titi) )
// ...
..)
Actuellement, dans mon cas, les logs sont supprimés en
recompilant (uniquement) getlog.cpp pour que getlog() renvoie
un wrapper "nul". Je réalise qu'on pourrait aisément avoir la
même chose avec un :
#define LOGGER if ( !log_are_enabled ) ; else dummy
et ainsi avoir un comportement dynamique, pour le coût d'un
if(). Je ne sais pas vraiment pourquoi, mais utiliser
#define LOGGER log_are_enabled && dummy
me parrait plus risqué.
C'est cependant plus ou moins ce qui se trouve dans la plupart
des macros pour assert. L'intérêt, comme j'ai dit, c'est que
c'est une expression, et qu'il peut servir (avec l'opérateur
virgule) dans des contextes où seulement une expression est
permise. La risque, évidemment, c'est aussi que c'est une
expression, ce qui donne davantage de possibilités à le faire
foirer : true || LOGGER << ..., par exemple,
Dans la pratique, je ne travaille pas avec des programmeurs qui
cherchent à détourner ce que j'ai fait à ce point-là, et je n'ai
pas vu des « accidents » avec l'expression qui n'ont pas
provoqué des erreurs de compilation.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
En effet, Loïc a proposé quelque chose de ce genre dernièrement. On a soit : #define LOGGER getlog( __FILE__, __LINE__ ) soit #define LOGGER if ( true ) ; else dummy (Note bien que dans ce cas-ci, même avec les logs désactivés lors de la compilation, il faut bien que ton programme contient un object dummy.)
C'est à peu près ce que j'ai dans mon appli, sauf que getlog() renvoie un stream qui wrapp std::cout/ofstream/... ou qui ne fait rien du tout. J'ai pas cherché à évaluer si le compilateur supprimait son utilisation, vu que jusque là je n'en n'ai pas éprouvé le besoin.
Tout à fait. Je n'ai jamais eu besoin de supprimer la configuration dynamique du log non plus -- correctement écrit et utilisé, les tests consument vraiment peu de temps. Mais la possibilité de pouvoir le faire a souvent été essentiel pour faire accepter politiquement le logging.
Ici aussi, on écrit ensuite : LOGGER << "x = " << x ;
(Au fond, je me démande si: #define LOGGER false && dummy ne serait pas mieux pour supprimer le log. Ça permettrait d'introduire des logs dans un initialisateur dans un constructeur, par exemple : Toto::Toto( int titi ) : myTiti( ((LOGGER << "titi = " << titi), titi) ) // ... ..)
Actuellement, dans mon cas, les logs sont supprimés en recompilant (uniquement) getlog.cpp pour que getlog() renvoie un wrapper "nul". Je réalise qu'on pourrait aisément avoir la même chose avec un :
#define LOGGER if ( !log_are_enabled ) ; else dummy
et ainsi avoir un comportement dynamique, pour le coût d'un if(). Je ne sais pas vraiment pourquoi, mais utiliser
#define LOGGER log_are_enabled && dummy
me parrait plus risqué.
C'est cependant plus ou moins ce qui se trouve dans la plupart des macros pour assert. L'intérêt, comme j'ai dit, c'est que c'est une expression, et qu'il peut servir (avec l'opérateur virgule) dans des contextes où seulement une expression est permise. La risque, évidemment, c'est aussi que c'est une expression, ce qui donne davantage de possibilités à le faire foirer : true || LOGGER << ..., par exemple,
Dans la pratique, je ne travaille pas avec des programmeurs qui cherchent à détourner ce que j'ai fait à ce point-là, et je n'ai pas vu des « accidents » avec l'expression qui n'ont pas provoqué des erreurs de compilation.
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34