J'utilise régulièrement des macros de préprocesseur de type objet comme indicateurs booléens dansCcode pour activer ou désactiver des sections de code.
Par exemple
#define DEBUG_PRINT 1
Et puis l'utiliser comme
#if(DEBUG_PRINT == 1)
printf("%s", "Testing");
#endif
Cependant, cela pose un problème si le fichier d’en-tête contenant le #define
est oublié d’être inclus dans le code source. Étant donné que la macro n'est pas déclarée, le préprocesseur la traite comme si elle était égale à 0 et l'instruction #if
ne s'exécutait jamais.
Lorsque le fichier d'en-tête est oublié pour être inclus, un comportement non attendu et indiscipliné peut se produire.
Idéalement, j'aimerais pouvoir vérifier à la fois qu'une macro est définie et qu'elle correspond à une certaine valeur, sur une ligne. S'il n'est pas défini, le préprocesseur renvoie une erreur (ou un avertissement).
Je cherche quelque chose comme:
#if-def-and-true-else-throw-error(DEBUG_PRINT)
...
#endif
C'est comme une combinaison de #ifdef
et #if
, et si elle n'existe pas, utilise #error
.
J'ai exploré quelques pistes, cependant, les directives de préprocesseur ne peuvent pas être utilisées dans un bloc #define
, et autant que je sache, il n'y a pas d'option de préprocesseur pour générer des erreurs/avertissements si une macro n'est pas définie lorsqu'elle est utilisée dans un #if
déclaration.
Cela peut ne pas fonctionner dans le cas général (je ne pense pas qu'il existe une solution générale à ce que vous demandez), mais pour votre exemple spécifique, vous pourriez envisager de changer cette séquence de code:
#if(DEBUG_PRINT == 1)
printf("%s", "Testing");
#endif
à:
if (DEBUG_PRINT == 1) {
printf("%s", "Testing");
}
Il n'y a plus de commentaires et échouera à la compilation si DEBUG_PRINT
n'est pas défini ou s'il est défini comme quelque chose qui ne peut être comparé à 1
.
pour autant que je sache, il n'y a pas d'option de préprocesseur pour générer des erreurs/avertissements si une macro n'est pas définie lorsqu'elle est utilisée dans une instruction
#if
.
Cela ne peut pas être une erreur car le standard C spécifie que le comportement est légal. À partir de la section 6.10.1/3 de la norme ISO C99:
Une fois que tous les remplacements dus à l’expansion des macros et à l’opérateur
defined
unaire Ont été effectués, tous les identificateurs restants sont remplacés par le numéro de pp0
....
Comme Jim Balter le note dans le commentaire ci-dessous, certains compilateurs (tels que gcc) peuvent émettre des avertissements à ce sujet. Cependant, puisque substituer 0
à des jetons de préprocesseur non reconnus est légal (et souvent souhaitable), je m'attendrais à ce que l'activation de tels avertissements génère beaucoup de bruit.
Il n'y a aucun moyen de faire exactement ce que vous voulez. Si vous souhaitez générer un échec de compilation si la macro n'est pas définie, vous devrez le faire explicitement.
#if !defined DEBUG_PRINT
#error DEBUG_PRINT is not defined.
#endif
pour chaque fichier source concerné. Vous pouvez également convertir votre macro en une macro de type fonction et éviter d'utiliser #if
. Par exemple, vous pouvez définir une macro DEBUG_PRINT
qui se développe en un appel printf
pour les versions de débogage, mais qui ne comporte plus rien pour les versions non-déboguées. Tout fichier qui omet d'inclure l'en-tête définissant la macro échouera lors de la compilation.
Plutôt que d'utiliser DEBUG_PRINT directement dans vos fichiers source, insérez ceci dans le fichier d'en-tête:
#if !defined(DEBUG_PRINT)
#error DEBUG_PRINT is not defined
#endif
#if DEBUG_PRINT
#define PrintDebug([args]) [definition]
#else
#define PrintDebug
#endif
Tout fichier source qui utilise PrintDebug mais n'inclut pas le fichier d'en-tête échouera lors de la compilation.
Si vous avez besoin que du code autre que les appels à PrintDebug soit compilé sur la base de DEBUG_PRINT, utilisez la suggestion de Michael Burr consistant à utiliser plain if
plutôt que #if
(oui, l'optimiseur ne générera pas de code dans un test de constante constant).
Edit: Et vous pouvez généraliser PrintDebug ci-dessus pour inclure ou exclure du code arbitraire tant que vous ne disposez pas de virgules ressemblant à des arguments de macro:
#if !defined(IF_DEBUG)
#error IF_DEBUG is not defined
#endif
#if IF_DEBUG
#define IfDebug(code) code
#else
#define IfDebug(code)
#endif
Ensuite, vous pouvez écrire des choses comme
IfDebug(int count1;) // IfDebug(int count1, count2;) won't work
IfDebug(int count2;)
...
IfDebug(count1++; count2++;)
Oui, vous pouvez vérifier les deux:
#if defined DEBUG && DEBUG == 1
# define D(...) printf(__VA_ARGS__)
#else
# define D(...)
#endif
Dans cet exemple, même lorsque #define DEBUG 0
est différent de 1, rien ne sera imprimé.
Vous pouvez même faire ceci:
#if defined DEBUG && DEBUG
# define D(...) printf(__VA_ARGS__)
#else
# define D(...)
#endif
Ici, si vous #define DEBUG 0
puis D(1,2,3)
, rien ne sera imprimé
Créez simplement une macro DEBUG_PRINT qui effectue l'impression réelle:
#define DEBUG_PRINT(n, str) \
\
if(n == 1) \
{ \
printf("%s", str); \
} \
else if(n == 2) \
{ \
do_something_else(); \
} \
\
#endif
#include <stdio.h>
int main()
{
DEBUG_PRINT(1, "testing");
}
Si la macro n'est pas définie, vous obtiendrez une erreur du compilateur car le symbole n'est pas reconnu.
#if 0 // 0/1
#define DEBUG_PRINT printf("%s", "Testing")
#else
#define DEBUG_PRINT printf("%s")
#endif
Donc, quand "si 0" ça ne fait rien et quand "si 1" ça va exécuter la macro définie.