wrote:Olivier Azeau wrote:
[...]PS : je ne sais pas si c'est off-topic tout ça (le
préprocesseur fait-il "partie du langage" ?)
Tout à fait. Section 16 de la norme, en ce qui concerne les
« directifs ». Quand on parle du préprocesseur, en fait, on
considère en général les six premières phase de traduction,
décrites en §2.1.
Ceci dit, ce n'est pas une raison d'en abuser. Dans la pratique,
c'est rarissime qu'on se sert de la compilation conditionnelle
dans le code bien écrit -- et jamais dans une fonction, comme il
en est question ici. (J'en ai quelques exemples qui trainent
dans le code à ma site, mais seulement dans les en-têtes, au
niveaux de portée du fichier.)
Voir par exemple
http://www.chris-lott.org/resources/cstyle/ifdefs.pdf.
Je suis d'accord pour proscrire la compilation conditionnelle en
dehors des en-têtes : sans aller jusqu'à une notion de code "bien
écrit", il s'agit surtout (pour moi) d'avoir un code lisible.
Je trouve cependant acceptable de se limiter à la présence de
macros
paramètrées à l'intérieur des fonctions car je ne connais aucun
idiome
(hors utilisation du pre-processeur) qui permette d'inhiber la
génération de code binaire superflu (en tirant, par exemple, parti
des
optimisations du compilateur).
cf par exemple le code de l'article que tu mentionnes :
#ifdef NDEBUG
# define DEBUG(list) /* nothing */
#else
# define DEBUG(list) printf list
#endif
DEBUG(("oops: %s %dn", b, c));
qui devient en C++ :
#ifdef NDEBUG
# define DEBUG(list) /* nothing */
#else
# define DEBUG(list) someDebugOutputStream << list << std::endl
#endif
DEBUG("oops: " << b << c);
kanze@gabi-soft.fr wrote:
Olivier Azeau wrote:
[...]
PS : je ne sais pas si c'est off-topic tout ça (le
préprocesseur fait-il "partie du langage" ?)
Tout à fait. Section 16 de la norme, en ce qui concerne les
« directifs ». Quand on parle du préprocesseur, en fait, on
considère en général les six premières phase de traduction,
décrites en §2.1.
Ceci dit, ce n'est pas une raison d'en abuser. Dans la pratique,
c'est rarissime qu'on se sert de la compilation conditionnelle
dans le code bien écrit -- et jamais dans une fonction, comme il
en est question ici. (J'en ai quelques exemples qui trainent
dans le code à ma site, mais seulement dans les en-têtes, au
niveaux de portée du fichier.)
Voir par exemple
http://www.chris-lott.org/resources/cstyle/ifdefs.pdf.
Je suis d'accord pour proscrire la compilation conditionnelle en
dehors des en-têtes : sans aller jusqu'à une notion de code "bien
écrit", il s'agit surtout (pour moi) d'avoir un code lisible.
Je trouve cependant acceptable de se limiter à la présence de
macros
paramètrées à l'intérieur des fonctions car je ne connais aucun
idiome
(hors utilisation du pre-processeur) qui permette d'inhiber la
génération de code binaire superflu (en tirant, par exemple, parti
des
optimisations du compilateur).
cf par exemple le code de l'article que tu mentionnes :
#ifdef NDEBUG
# define DEBUG(list) /* nothing */
#else
# define DEBUG(list) printf list
#endif
DEBUG(("oops: %s %dn", b, c));
qui devient en C++ :
#ifdef NDEBUG
# define DEBUG(list) /* nothing */
#else
# define DEBUG(list) someDebugOutputStream << list << std::endl
#endif
DEBUG("oops: " << b << c);
wrote:Olivier Azeau wrote:
[...]PS : je ne sais pas si c'est off-topic tout ça (le
préprocesseur fait-il "partie du langage" ?)
Tout à fait. Section 16 de la norme, en ce qui concerne les
« directifs ». Quand on parle du préprocesseur, en fait, on
considère en général les six premières phase de traduction,
décrites en §2.1.
Ceci dit, ce n'est pas une raison d'en abuser. Dans la pratique,
c'est rarissime qu'on se sert de la compilation conditionnelle
dans le code bien écrit -- et jamais dans une fonction, comme il
en est question ici. (J'en ai quelques exemples qui trainent
dans le code à ma site, mais seulement dans les en-têtes, au
niveaux de portée du fichier.)
Voir par exemple
http://www.chris-lott.org/resources/cstyle/ifdefs.pdf.
Je suis d'accord pour proscrire la compilation conditionnelle en
dehors des en-têtes : sans aller jusqu'à une notion de code "bien
écrit", il s'agit surtout (pour moi) d'avoir un code lisible.
Je trouve cependant acceptable de se limiter à la présence de
macros
paramètrées à l'intérieur des fonctions car je ne connais aucun
idiome
(hors utilisation du pre-processeur) qui permette d'inhiber la
génération de code binaire superflu (en tirant, par exemple, parti
des
optimisations du compilateur).
cf par exemple le code de l'article que tu mentionnes :
#ifdef NDEBUG
# define DEBUG(list) /* nothing */
#else
# define DEBUG(list) printf list
#endif
DEBUG(("oops: %s %dn", b, c));
qui devient en C++ :
#ifdef NDEBUG
# define DEBUG(list) /* nothing */
#else
# define DEBUG(list) someDebugOutputStream << list << std::endl
#endif
DEBUG("oops: " << b << c);
Michael Moreno wrote:Tu pratiques l'obfuscation active ?
Comment puis-je faire pour debugger sans utiliser la compilation
conditionnelle ?
chez moi ca s'arrete a :
#if_Debug
OutputDebugString("...");
#end if
Je ne veux pas aller plus loin que cela.
Dans ce cas, considère peut être qqe chose comme :
#define DEBUG_OUTPUT(data) { std::ostringstream s; s << data << 'n';
OutputDebugString(s.str().c_str()); }
DEBUG_OUTPUT( "..." << x << "..." );
qui est, à mon goût, plus lisible.
Michael Moreno wrote:
Tu pratiques l'obfuscation active ?
Comment puis-je faire pour debugger sans utiliser la compilation
conditionnelle ?
chez moi ca s'arrete a :
#if_Debug
OutputDebugString("...");
#end if
Je ne veux pas aller plus loin que cela.
Dans ce cas, considère peut être qqe chose comme :
#define DEBUG_OUTPUT(data) { std::ostringstream s; s << data << 'n';
OutputDebugString(s.str().c_str()); }
DEBUG_OUTPUT( "..." << x << "..." );
qui est, à mon goût, plus lisible.
Michael Moreno wrote:Tu pratiques l'obfuscation active ?
Comment puis-je faire pour debugger sans utiliser la compilation
conditionnelle ?
chez moi ca s'arrete a :
#if_Debug
OutputDebugString("...");
#end if
Je ne veux pas aller plus loin que cela.
Dans ce cas, considère peut être qqe chose comme :
#define DEBUG_OUTPUT(data) { std::ostringstream s; s << data << 'n';
OutputDebugString(s.str().c_str()); }
DEBUG_OUTPUT( "..." << x << "..." );
qui est, à mon goût, plus lisible.
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Même dans un environement multi-threadé, sans s'occuper des locks.)
Quelque soit la solution adoptée, il y aura un en-tête du genre
log.hh,
où les macros sont défini. Si jamais il fallait les supprimer
complètement pour des raisons de performance, c'est une version
différente de l'en-tête qui sert, choisi au moyen d'une option -I.
(Mais
ça ne m'est jamais arrivé, et dans les applications plus grosses, la
présence d'un log configurable fait souvent partie du cahier de
charges.)
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Même dans un environement multi-threadé, sans s'occuper des locks.)
Quelque soit la solution adoptée, il y aura un en-tête du genre
log.hh,
où les macros sont défini. Si jamais il fallait les supprimer
complètement pour des raisons de performance, c'est une version
différente de l'en-tête qui sert, choisi au moyen d'une option -I.
(Mais
ça ne m'est jamais arrivé, et dans les applications plus grosses, la
présence d'un log configurable fait souvent partie du cahier de
charges.)
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Même dans un environement multi-threadé, sans s'occuper des locks.)
Quelque soit la solution adoptée, il y aura un en-tête du genre
log.hh,
où les macros sont défini. Si jamais il fallait les supprimer
complètement pour des raisons de performance, c'est une version
différente de l'en-tête qui sert, choisi au moyen d'une option -I.
(Mais
ça ne m'est jamais arrivé, et dans les applications plus grosses, la
présence d'un log configurable fait souvent partie du cahier de
charges.)
wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les éléments
envoyés dans le flux vont toujours être évalués, même lorsque le log est
désactivé.
kanze@gabi-soft.fr wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les éléments
envoyés dans le flux vont toujours être évalués, même lorsque le log est
désactivé.
wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les éléments
envoyés dans le flux vont toujours être évalués, même lorsque le log est
désactivé.
wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les éléments
envoyés dans le flux vont toujours être évalués, même lorsque le log est
désactivé.
kanze@gabi-soft.fr wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les éléments
envoyés dans le flux vont toujours être évalués, même lorsque le log est
désactivé.
wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les éléments
envoyés dans le flux vont toujours être évalués, même lorsque le log est
désactivé.
wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet
des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les
éléments envoyés dans le flux vont toujours être évalués, m ême
lorsque
le log est désactivé.
Même dans un environement multi-threadé, sans s'occuper des
locks.)
Quelque soit la solution adoptée, il y aura un en-tête du genre
log.hh, où les macros sont défini. Si jamais il fallait les
supprimer complètement pour des raisons de performance, c'est une
version différente de l'en-tête qui sert, choisi au moyen d'une
option -I. (Mais ça ne m'est jamais arrivé, et dans les
applications
plus grosses, la présence d'un log configurable fait souvent
partie
du cahier de charges.)
Oui, mais il est des applications sur poste client que l'on veut les
plus légères possibles au niveau CPU (genre tache de fond avec
zéro
impact sur l'utilisateur de la machine)
kanze@gabi-soft.fr wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet
des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les
éléments envoyés dans le flux vont toujours être évalués, m ême
lorsque
le log est désactivé.
Même dans un environement multi-threadé, sans s'occuper des
locks.)
Quelque soit la solution adoptée, il y aura un en-tête du genre
log.hh, où les macros sont défini. Si jamais il fallait les
supprimer complètement pour des raisons de performance, c'est une
version différente de l'en-tête qui sert, choisi au moyen d'une
option -I. (Mais ça ne m'est jamais arrivé, et dans les
applications
plus grosses, la présence d'un log configurable fait souvent
partie
du cahier de charges.)
Oui, mais il est des applications sur poste client que l'on veut les
plus légères possibles au niveau CPU (genre tache de fond avec
zéro
impact sur l'utilisateur de la machine)
wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet
des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les
éléments envoyés dans le flux vont toujours être évalués, m ême
lorsque
le log est désactivé.
Même dans un environement multi-threadé, sans s'occuper des
locks.)
Quelque soit la solution adoptée, il y aura un en-tête du genre
log.hh, où les macros sont défini. Si jamais il fallait les
supprimer complètement pour des raisons de performance, c'est une
version différente de l'en-tête qui sert, choisi au moyen d'une
option -I. (Mais ça ne m'est jamais arrivé, et dans les
applications
plus grosses, la présence d'un log configurable fait souvent
partie
du cahier de charges.)
Oui, mais il est des applications sur poste client que l'on veut les
plus légères possibles au niveau CPU (genre tache de fond avec
zéro
impact sur l'utilisateur de la machine)
Olivier Azeau writes:wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet
des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les
éléments envoyés dans le flux vont toujours être évalués,
même
lorsque le log est désactivé.
Non, grâce au court-circuit de « && ».
Olivier Azeau <john@doe.com> writes:
kanze@gabi-soft.fr wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet
des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les
éléments envoyés dans le flux vont toujours être évalués,
même
lorsque le log est désactivé.
Non, grâce au court-circuit de « && ».
Olivier Azeau writes:wrote:(La fonction Log::log renvoie un flux « wrappé », ce qui permet
des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que les
éléments envoyés dans le flux vont toujours être évalués,
même
lorsque le log est désactivé.
Non, grâce au court-circuit de « && ».
Olivier Azeau wrote:
wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que
les éléments envoyés dans le flux vont toujours être évalués,
même lorsque le log est désactivé.
La même chose peut s'écrire un peu comme :
#define DEBUG if (!isLogEnabled) ; else Log::log(__FILE__, __LINE__ )
Olivier Azeau wrote:
kanze@gabi-soft.fr wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que
les éléments envoyés dans le flux vont toujours être évalués,
même lorsque le log est désactivé.
La même chose peut s'écrire un peu comme :
#define DEBUG if (!isLogEnabled) ; else Log::log(__FILE__, __LINE__ )
Olivier Azeau wrote:
wrote:
(La fonction Log::log renvoie un flux « wrappé », ce qui permet des
choses comme :
DEBUG << "var = " << var ;
ou
ERROR << "c'est raté" ;
Le seul truc qui me gêne dans une telle solution c'est que
les éléments envoyés dans le flux vont toujours être évalués,
même lorsque le log est désactivé.
La même chose peut s'écrire un peu comme :
#define DEBUG if (!isLogEnabled) ; else Log::log(__FILE__, __LINE__ )
Évidemment, un faible coût n'est pas zéro, et le cas échéant, rien
n'empèche de combiner les deux : de n'utiliser le LogStream temporaire
qu'après avoir vérifier que le log est actif. Parfois même, par
exemple
quand on veut sortir un tableau, c'est prèsque nécessaire :
if ( Log::isActive( Log::debug ) ) {
LogStream dest = Log::stream( Log::debug, __FILE__, __LINE__ )
;
dest << "En-tête de tableaun" ;
for ( Tableau::const_iterator i = t.begin() ;
i != t.end() ;
++ i ) {
dest << *i << 'n' ;
}
}
Évidemment, un faible coût n'est pas zéro, et le cas échéant, rien
n'empèche de combiner les deux : de n'utiliser le LogStream temporaire
qu'après avoir vérifier que le log est actif. Parfois même, par
exemple
quand on veut sortir un tableau, c'est prèsque nécessaire :
if ( Log::isActive( Log::debug ) ) {
LogStream dest = Log::stream( Log::debug, __FILE__, __LINE__ )
;
dest << "En-tête de tableaun" ;
for ( Tableau::const_iterator i = t.begin() ;
i != t.end() ;
++ i ) {
dest << *i << 'n' ;
}
}
Évidemment, un faible coût n'est pas zéro, et le cas échéant, rien
n'empèche de combiner les deux : de n'utiliser le LogStream temporaire
qu'après avoir vérifier que le log est actif. Parfois même, par
exemple
quand on veut sortir un tableau, c'est prèsque nécessaire :
if ( Log::isActive( Log::debug ) ) {
LogStream dest = Log::stream( Log::debug, __FILE__, __LINE__ )
;
dest << "En-tête de tableaun" ;
for ( Tableau::const_iterator i = t.begin() ;
i != t.end() ;
++ i ) {
dest << *i << 'n' ;
}
}
writes:Évidemment, un faible coût n'est pas zéro, et le cas échéant,
rien
n'empèche de combiner les deux : de n'utiliser le LogStream
temporaire qu'après avoir vérifier que le log est actif. Parfois
même, par exemple quand on veut sortir un tableau, c'est prèsque
nécessaire :
if ( Log::isActive( Log::debug ) ) {
LogStream dest = Log::stream( Log::debug, __FILE__, __LINE__ )
;
dest << "En-tête de tableaun" ;
for ( Tableau::const_iterator i = t.begin() ;
i != t.end() ;
++ i ) {
dest << *i << 'n' ;
}
}
Dans ce cas, je verrais bien, en utilisant Boost.Lambda, quelque
chose comme :
DEBUG
<< "Le tableau : "
<< LogForEach( t.begin() , t.end() , _1 << "n " << _2 ) ;
où « _1 » représente le flux de logging.
Toujours avec DEBUG défini comme :
#define DEBUG LogManager::enabled( LogManager::debug )
&& LogManager::stream( LogManager::debug )
kanze@gabi-soft.fr writes:
Évidemment, un faible coût n'est pas zéro, et le cas échéant,
rien
n'empèche de combiner les deux : de n'utiliser le LogStream
temporaire qu'après avoir vérifier que le log est actif. Parfois
même, par exemple quand on veut sortir un tableau, c'est prèsque
nécessaire :
if ( Log::isActive( Log::debug ) ) {
LogStream dest = Log::stream( Log::debug, __FILE__, __LINE__ )
;
dest << "En-tête de tableaun" ;
for ( Tableau::const_iterator i = t.begin() ;
i != t.end() ;
++ i ) {
dest << *i << 'n' ;
}
}
Dans ce cas, je verrais bien, en utilisant Boost.Lambda, quelque
chose comme :
DEBUG
<< "Le tableau : "
<< LogForEach( t.begin() , t.end() , _1 << "n " << _2 ) ;
où « _1 » représente le flux de logging.
Toujours avec DEBUG défini comme :
#define DEBUG LogManager::enabled( LogManager::debug )
&& LogManager::stream( LogManager::debug )
writes:Évidemment, un faible coût n'est pas zéro, et le cas échéant,
rien
n'empèche de combiner les deux : de n'utiliser le LogStream
temporaire qu'après avoir vérifier que le log est actif. Parfois
même, par exemple quand on veut sortir un tableau, c'est prèsque
nécessaire :
if ( Log::isActive( Log::debug ) ) {
LogStream dest = Log::stream( Log::debug, __FILE__, __LINE__ )
;
dest << "En-tête de tableaun" ;
for ( Tableau::const_iterator i = t.begin() ;
i != t.end() ;
++ i ) {
dest << *i << 'n' ;
}
}
Dans ce cas, je verrais bien, en utilisant Boost.Lambda, quelque
chose comme :
DEBUG
<< "Le tableau : "
<< LogForEach( t.begin() , t.end() , _1 << "n " << _2 ) ;
où « _1 » représente le flux de logging.
Toujours avec DEBUG défini comme :
#define DEBUG LogManager::enabled( LogManager::debug )
&& LogManager::stream( LogManager::debug )