50 votes

Forcer le compilateur à ignorer certaines lignes du programme

Supposons que j'ai 10 000 lignes de code C++. 200 lignes de ce code sont destinées à des tests (par exemple, vérifier le programme et afficher un message d'erreur).

Existe-t-il un moyen en C++ d'ignorer ou de prendre en compte certaines lignes du code (peut-être à l'aide de préprocesseur mots-clés) ?

78voto

herohuyongtao Points 13552

Réponse courte :

Utilisez macros y #ifdef vérification. Par exemple :

#ifdef MY_CONTROL_MACRO
...
#endif

le code à l'intérieur de cette portée ne sera compilé que si vous avez déjà défini l'attribut MY_CONTROL_MACRO macro.


Plus de choses :

  1. Pour définir une telle macro, vous pouvez

    • Ajouter #define MY_CONTROL_MACRO à votre code. Ou bien,
    • Pour VS, ajoutez MY_CONTROL_MACRO à Project > Properties > C/C++ > Preprocessor > Preprocessor Definitions . Ou,
    • Pour GCC, compilez votre code avec l'option -DMY_CONTROL_MACRO .
  2. Vous pouvez consulter aquí pour plus d'informations.

    Ce bloc est appelé un groupe conditionnel. Le texte contrôlé sera inclus dans la sortie du préprocesseur si et seulement si MACRO est défini. Nous disons que la conditionnelle réussit si MACRO est définie, échoue si elle ne l'est pas.

    Le texte contrôlé à l'intérieur d'une condition peut inclure des directives de prétraitement. Celles-ci ne sont exécutées que si la conditionnelle réussit. Vous pouvez imbriquer des groupes conditionnels dans d'autres groupes conditionnels, mais ils doivent être complètement imbriqués. En d'autres termes, "#endif" correspond toujours au "#ifdef" (ou "#ifndef", ou "#if") le plus proche. En outre, vous ne pouvez pas commencer un groupe conditionnel dans un fichier et le terminer dans un autre.

  3. Vous pouvez également utiliser la fonction avancée ifdef-else-endif le style :

    #ifdef MY_CONTROL_MACRO
        ... // this part will be valid if MY_CONTROL_MACRO is defined
    #else
        ... // this part will be valid if MY_CONTROL_MACRO is NOT defined
    #endif

13voto

Michael Aaron Safyan Points 45071

Entourez le code de "#ifdef...#endif", puis utilisez les options du compilateur pour définir l'indicateur :

#ifdef MYTEST_ONLY_FUNCTIONALITY_ENABLED
...
#endif

Vous pouvez ensuite utiliser les options du compilateur pour inclure ce code. Par exemple, dans GCC :

-DMYTEST_ONLY_FUNCTIONALITY_ENABLED

Bien que, pour être honnête, je pense que cette approche n'est généralement pas très maintenable dans les grands projets et, si possible, il est généralement préférable de simplement déplacer le code de test uniquement dans une bibliothèque complètement séparée (sans cette logique conditionnelle) et simplement lier ce code dans votre binaire de test plutôt que votre binaire non-test. Cela évite également de devoir compiler chacune des autres bibliothèques en mode débogage et non débogage.

6voto

6502 Points 42700

C'est ce que #ifdef a été conçu pour

Vous mettez

#ifdef TESTS
... test code ...
#endif

et ensuite vous pouvez passer aux options du compilateur pour décider si vous voulez que la partie test soit compilée ou non. Par exemple, avec g++, c'est

g++ -DTESTS ...

4voto

TheDuke Points 526

L'utilisation d'une garde de préprocesseur est certainement l'approche la plus flexible et la plus courante. Cependant, lorsque cela est possible, je suggère d'utiliser une instruction if. Par exemple, au lieu de

void example(int a){
   int some_local;
   ...
   #ifdef _DEBUG
   std::cout << "In function " << __FUNCTION__ << "(" << a <<")" << std::endl;
   #endif
   ....
}

En supposant que ENABLE_DEBUG est défini comme étant 0 ou non nul, j'utiliserais

void example(int a){
   int some_local;

   ...
   if(ENABLE_DEBUG) std::cout << "In function " << __FUNCTION__ << "(" << a <<")" << std::endl;
   ...
}

Puisque ENABLE_DEBUG est une constante, lorsque ENABLE_DEBUG est 0, le compilateur ne génère aucun code pour les instructions qu'il garde. Alors, pourquoi utiliser cette méthode au lieu de #ifdef ?

  1. S'il y a de nombreuses déclarations de débogage distinctes réparties dans le code, la lecture peut être un peu plus aisée.
  2. Plus important encore, le code est toujours traité pour détecter les erreurs syntaxiques, même si aucun code n'est généré. Cela peut être très utile si le code de débogage n'est pas fréquemment activé. Si les variables changent (par exemple, dans l'exemple ci-dessus, si l'argument a a été renommé), la personne qui effectue le changement saura qu'elle doit également mettre à jour la déclaration de débogage. Si des #ifdefs sont utilisés, cela peut cacher un peu de pourriture jusqu'à ce que quelqu'un ait besoin d'activer le code de débogage et qu'il doive alors aller essayer de corriger le code, ce qui n'est pas forcément évident pour lui.

Évidemment, cette approche ne fonctionne que pour les déclarations de débogage à l'intérieur des corps de méthodes/fonctions.

3voto

Michael Hampton Points 3441

Allez-y avec le existant et utiliser la convention NDEBUG macro. Tous les compilateurs courants définissent cette macro pour libérer et ne le définissent pas pour les déboguer les constructions.

Cette macro existait à l'origine pour contrôler la sortie de assert(3) et est défini comme tel depuis le début. dans la norme POSIX et au moins depuis C89.

Notez que vous devez inverser le test avec #ifndef .

Un exemple :

#ifndef NDEBUG
    /* Debugging code */
    std::cerr << "So far we have seen " << unicorns << " unicorns" << std::endl;
#endif

P.S. Avec gcc / g++ vous faites une construction de débogage en ajoutant -g à la ligne de commande.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X