C'est peut-être une question de style, mais il y a un peu de division dans notre équipe de développement et je me suis demandé si quelqu'un d'autre avait des idées à ce sujet ...
Fondamentalement, nous avons des instructions d'impression de débogage que nous désactivons pendant le développement normal. Personnellement, je préfère faire ce qui suit:
//---- SomeSourceFile.cpp ----
#define DEBUG_ENABLED (0)
...
SomeFunction()
{
int someVariable = 5;
#if(DEBUG_ENABLED)
printf("Debugging: someVariable == %d", someVariable);
#endif
}
Certains membres de l'équipe préfèrent cependant ce qui suit:
// #define DEBUG_ENABLED
...
SomeFunction()
{
int someVariable = 5;
#ifdef DEBUG_ENABLED
printf("Debugging: someVariable == %d", someVariable);
#endif
}
... laquelle de ces méthodes vous convient le mieux et pourquoi? Mon sentiment est que le premier est plus sûr parce qu'il y a toujours quelque chose de défini et qu'il n'y a aucun danger que cela puisse détruire d'autres définitions ailleurs.
c++
c
if-statement
coding-style
c-preprocessor
Jon Cage
la source
la source
#if
, vous pouvez également utiliser#elif
de manière cohérente, contrairement à#ifdef
. Ainsi, au lieu de simplement utiliser#define BLAH
, utilisez#define BLAH 1
avec#if BLAH
, etc ...Réponses:
Ma première réaction a été
#ifdef
, bien sûr , mais je pense que cela#if
présente en fait des avantages significatifs - voici pourquoi:Tout d'abord, vous pouvez utiliser
DEBUG_ENABLED
dans le préprocesseur et les tests compilés. Exemple - Souvent, je veux des délais d'expiration plus longs lorsque le débogage est activé, donc en utilisant#if
, je peux écrire ceci... au lieu de ...
Deuxièmement, vous êtes mieux placé si vous souhaitez migrer d'une
#define
constante à une constante globale.#define
s sont généralement mal vus par la plupart des programmeurs C ++.Et, troisièmement, vous dites que votre équipe est divisée. Je suppose que cela signifie que différents membres ont déjà adopté des approches différentes et que vous devez normaliser. La décision qui
#if
est le choix préféré signifie que le code utilisant#ifdef
sera compilé - et exécuté - même si la valeurDEBUG_ENABLED
est false. Et il est beaucoup plus facile de retrouver et de supprimer la sortie de débogage qui est produite alors qu'elle ne devrait pas l'être que vice-versa.Oh, et un petit point de lisibilité. Vous devriez pouvoir utiliser true / false plutôt que 0/1 dans votre
#define
, et comme la valeur est un seul jeton lexical, c'est la seule fois où vous n'avez pas besoin de parenthèses autour d'elle.au lieu de
la source
#ifdef
est que cela fonctionne avec des choses qui ne sont pas définies; qu'ils ne soient pas définis intentionnellement ou à cause d'une faute de frappe ou quoi que ce soit.#if DEBUG_ENBALED
n'est pas une erreur détectée par le préprocesseur. SiDEBUG_ENBALED
n'est pas défini, il s'étend au jeton0
dans les#if
directives.Ils sont tous les deux hideux. Au lieu de cela, faites ceci:
Ensuite, chaque fois que vous avez besoin de code de débogage, mettez-le à l'intérieur
D();
. Et votre programme n'est pas pollué par des labyrinthes hideux#ifdef
.la source
#ifdef
vérifie simplement si un jeton est défini, donnépuis
la source
Nous avons eu le même problème sur plusieurs fichiers et il y a toujours le problème avec les gens qui oublient d'inclure un fichier «indicateur de fonctionnalités» (avec une base de code de> 41 000 fichiers, c'est facile à faire).
Si vous aviez feature.h:
Mais ensuite, vous avez oublié d'inclure le fichier d'en-tête dans file.cpp:
Ensuite, vous avez un problème, le compilateur interprète COOL_FEATURE étant indéfini comme un "faux" dans ce cas et ne parvient pas à inclure le code. Oui, gcc prend en charge un indicateur qui provoque une erreur pour les macros non définies ... mais la plupart des codes tiers définissent ou ne définissent pas les fonctionnalités, donc ce ne serait pas si portable.
Nous avons adopté un moyen portable de corriger ce cas ainsi que de tester l'état d'une fonctionnalité: les macros de fonction.
si vous avez changé le feature.h ci-dessus en:
Mais vous avez à nouveau oublié d'inclure le fichier d'en-tête dans file.cpp:
Le préprocesseur se serait trompé en raison de l'utilisation d'une macro de fonction non définie.
la source
Pour effectuer une compilation conditionnelle, #if et #ifdef sont presque identiques, mais pas tout à fait. Si votre compilation conditionnelle dépend de deux symboles, #ifdef ne fonctionnera pas aussi bien. Par exemple, supposons que vous ayez deux symboles de compilation conditionnelle, PRO_VERSION et TRIAL_VERSION, vous pourriez avoir quelque chose comme ceci:
Utiliser #ifdef ce qui précède devient beaucoup plus compliqué, en particulier pour faire fonctionner la partie #else.
Je travaille sur du code qui utilise beaucoup la compilation conditionnelle et nous avons un mélange de #if & #ifdef. Nous avons tendance à utiliser # ifdef / # ifndef pour le cas simple et #if chaque fois que deux symboles ou plus sont en cours d'évaluation.
la source
#if defined
quoi estdefined
-ce un mot clé ou?Je pense que c'est entièrement une question de style. Ni l'un ni l'autre n'a vraiment d'avantage évident sur l'autre.
La cohérence est plus importante que l'un ou l'autre choix particulier, donc je vous recommande de vous réunir avec votre équipe et de choisir un style et de vous y tenir.
la source
Je préfère moi-même:
Comme il est plus facile de créer du code qui recherche la condition opposée beaucoup plus facile à repérer:
contre.
la source
#if ! defined
pour rendre le!
plus visible et difficile à manquer.C'est une question de style. Mais je recommande une manière plus concise de le faire:
Vous faites cela une fois, puis utilisez toujours debug_print () pour imprimer ou ne rien faire. (Oui, cela compilera dans les deux cas.) De cette façon, votre code ne sera pas brouillé avec les directives du préprocesseur.
Si vous obtenez l'avertissement "expression n'a aucun effet" et que vous souhaitez vous en débarrasser, voici une alternative:
la source
#if
vous donne la possibilité de le régler sur 0 pour désactiver la fonctionnalité, tout en détectant toujours que le commutateur est là.Personnellement, je peux toujours l'
#define DEBUG 1
attraper avec un #if ou un #ifdefla source
#define DEBUG 1
. Not#define DEBUG=1
#if et #define MY_MACRO (0)
L'utilisation de #if signifie que vous avez créé une macro "define", c'est-à-dire quelque chose qui sera recherché dans le code pour être remplacé par "(0)". C'est «l'enfer des macros» que je déteste voir en C ++, car il pollue le code avec des modifications potentielles du code.
Par exemple:
donne l'erreur suivante sur g ++:
Une seule erreur.
Ce qui signifie que votre macro a interagi avec succès avec votre code C ++: l'appel à la fonction a réussi. Dans ce cas simple, c'est amusant. Mais ma propre expérience avec des macros jouant en silence avec mon code n'est pas pleine de joie et de plénitude, alors ...
#ifdef et #define MY_MACRO
Utiliser #ifdef signifie que vous «définissez» quelque chose. Non pas que vous lui donniez une valeur. Il est toujours polluant, mais au moins, il sera "remplacé par rien", et non vu par le code C ++ comme une instruction de code retardée. Le même code ci-dessus, avec une définition simple, il:
Donne les avertissements suivants:
Alors...
Conclusion
Je préfère vivre sans macros dans mon code, mais pour plusieurs raisons (définition de protections d'en-tête ou macros de débogage), je ne peux pas.
Mais au moins, j'aime les rendre le moins interactif possible avec mon code C ++ légitime. Ce qui signifie utiliser #define sans valeur, utiliser #ifdef et #ifndef (ou même #if défini comme suggéré par Jim Buck), et surtout, leur donner des noms si longs et si extraterrestres que personne dans son bon sens n'utilisera il "par hasard", et cela n'affectera en aucun cas le code C ++ légitime.
Post Scriptum
Maintenant, alors que je relis mon article, je me demande si je ne devrais pas essayer de trouver une valeur qui ne sera jamais correcte en C ++ à ajouter à ma définition. Quelque chose comme
qui pourrait être utilisé avec #ifdef et #ifndef, mais ne laissez pas le code se compiler s'il est utilisé dans une fonction ... J'ai essayé cela avec succès sur g ++, et cela a donné l'erreur:
Intéressant. :-)
la source
Ce n'est pas du tout une question de style. La question est également malheureusement erronée. Vous ne pouvez pas comparer ces directives de préprocesseur dans le sens de meilleure ou plus sûre.
signifie "si la macro est définie" ou "si la macro existe". La valeur de macro n'a pas d'importance ici. Cela peut être n'importe quoi.
si toujours comparer à une valeur. Dans l'exemple ci-dessus, il s'agit de la comparaison implicite standard:
exemple d'utilisation de #if
vous pouvez maintenant mettre la définition de CFLAG_EDITION soit dans votre code
ou vous pouvez définir la macro comme indicateur du compilateur. Voir aussi ici .
la source
Le premier me paraît plus clair. Il semble plus naturel d'en faire un drapeau par rapport à défini / non défini.
la source
Les deux sont exactement équivalents. En utilisation idiomatique, #ifdef est utilisé uniquement pour vérifier la définition (et ce que j'utiliserais dans votre exemple), alors que #if est utilisé dans des expressions plus complexes, telles que #if défini (A) &&! Défini (B).
la source
Un peu OT, mais activer / désactiver la journalisation avec le préprocesseur est définitivement sous-optimal en C ++. Il existe de bons outils de journalisation comme log4cxx d'Apache qui sont open-source et ne limitent pas la façon dont vous distribuez votre application. Ils vous permettent également de modifier les niveaux de journalisation sans recompilation, ont une très faible surcharge si vous désactivez la journalisation et vous donnent la possibilité de désactiver complètement la journalisation en production.
la source
J'avais l'habitude d'utiliser
#ifdef
, mais quand je suis passé à Doxygen pour la documentation, j'ai trouvé que les macros commentées ne peuvent pas être documentées (ou, du moins, Doxygen produit un avertissement). Cela signifie que je ne peux pas documenter les macros de changement de fonctionnalité qui ne sont pas actuellement activées.Bien qu'il soit possible de définir les macros uniquement pour Doxygen, cela signifie que les macros dans les parties non actives du code seront également documentées. Personnellement, je souhaite afficher les commutateurs de fonctionnalités et ne documenter que ce qui est actuellement sélectionné. De plus, cela rend le code assez compliqué si de nombreuses macros doivent être définies uniquement lorsque Doxygen traite le fichier.
Par conséquent, dans ce cas, il vaut mieux toujours définir les macros et utiliser
#if
.la source
J'ai toujours utilisé #ifdef et les drapeaux du compilateur pour le définir ...
la source
Vous pouvez également déclarer une constante globale et utiliser le C ++ if, au lieu du préprocesseur #if. Le compilateur devrait optimiser les branches inutilisées pour vous, et votre code sera plus propre.
Voici ce que C ++ Gotchas de Stephen C. Dewhurst dit à propos de l'utilisation des # if.
la source
Il existe une différence dans le cas d'une manière différente de spécifier une définition conditionnelle au pilote:
production:
Cela signifie que
-DA
c'est synonyme de-DA=1
et si la valeur est omise, cela peut entraîner des problèmes en cas d'#if A
utilisation.la source
J'aime
#define DEBUG_ENABLED (0)
quand vous voudrez peut-être plusieurs niveaux de débogage. Par exemple:Facilite le débogage des fuites de mémoire, sans avoir toutes ces lignes de journal dans votre manière de déboguer d'autres choses.
De plus, le
#ifndef
contour de la définition facilite la sélection d'un niveau de débogage spécifique sur la ligne de commande:Sinon, je donnerais l'avantage à
#ifdef
parce que l'indicateur compilateur / make serait remplacé par celui du fichier. Vous n'avez donc pas à vous soucier de changer l'en-tête avant de faire la validation.la source