web-dev-qa-db-fra.com

Forcer le compilateur à ignorer certaines lignes du programme

Supposons que j'ai 10 000 lignes de code C++. 200 lignes de ce code sont à des fins de test (par exemple, vérifiez le programme et affichez un message d'erreur).

Existe-t-il un moyen en C++ d'ignorer ou de considérer certaines lignes du code (peut-être avec préprocesseur mots-clés)?

48
user1436187

Réponse courte:

Utilisez les macros et #ifdef vérification. Par exemple:

#ifdef MY_CONTROL_MACRO
...
#endif

le code dans cette étendue ne sera compilé que si vous avez déjà défini le MY_CONTROL_MACRO macro.


Plus de choses:

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

    • Ajouter #define MY_CONTROL_MACRO à votre code. Ou,
    • 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 ici 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 le conditionnel réussit si MACRO est défini, échoue s'il ne l'est pas.

    Le texte contrôlé à l'intérieur d'un conditionnel peut inclure des directives de prétraitement. Ils ne sont exécutés que si le conditionnel 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" le plus proche (ou "#ifndef" ou "#if"). En outre, vous ne pouvez pas démarrer un groupe conditionnel dans un fichier et le terminer dans un autre.

  3. Vous pouvez également utiliser la fonction avancée ifdef-else-endif 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
    
78
herohuyongtao

Entourez le code avec "#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 vers une bibliothèque complètement séparée (sans cette logique conditionnelle) et de simplement lier cela code dans votre binaire de test plutôt que dans votre binaire non-test. Cela évite également d'avoir à compiler chacune des autres bibliothèques en mode débogage et non débogage.

13

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

Tu mets

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

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

g++ -DTESTS ...
6
6502

L'utilisation d'une protection 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 vaut 0, le compilateur ne générera aucun code pour les instructions qu'il garde. Alors, pourquoi utiliser cette méthode au lieu de #ifdef?

  1. S'il existe de nombreuses instructions de débogage distinctes réparties dans le code, il peut être un peu plus facile à lire
  2. Plus important encore, le code est toujours traité pour 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 effectuant la modification saura qu'elle doit également mettre à jour l'instruction de débogage. Si #ifdefs est utilisé, cela peut cacher la pourriture des bits jusqu'à ce que quelqu'un ait besoin d'activer le code de débogage, puis il doit essayer de corriger le code, ce qui peut ne pas être évident pour eux.

De toute évidence, cette approche ne fonctionne que pour les instructions de débogage à l'intérieur des corps de méthode/fonction.

4
TheDuke

Utilisez la convention existante et utilisez la macro NDEBUG. Tous les compilateurs courants définissent cette macro pour les versions de la version et ne la définissent pas pour le débogage construit.

La macro existait à l'origine pour contrôler la sortie de assert(3), et est définie comme telle tout le long du chemin 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 effectuez une version de débogage en ajoutant -g à la ligne de commande.

3
Michael Hampton

Utilisez le préprocesseur #define et #if

selon votre compilateur, vous devriez avoir certaines variables disponibles par défaut, à savoir NDEBUG (pour non-débogage) ou DEBUG

vous pouvez définir vous-même une variable dans le code en

#define MY_VARIABLE

et l'utiliser comme suit

#ifdef MY_VARIABLE
  //code that compiles only if MY_VARIABLE is defined
  printf("test output here");
#else
  //code that compiles only if MY_VARIABLE is NOT defined
  printf("MY_VARIABLE is not defined");
#endif

pour plus d'informations, recherchez en ligne

#define, #if, #ifdef, #ifndef
2
user3218782

Entourez votre code de test #ifdef DEBUG.

#if DEBUG
   ....
#endif
2
Richard Schneider

La voie à suivre est d'utiliser la directive du préprocesseur avec le define passé au compilateur ou extrait d'un en-tête "config.h":

#if defined(DEBUG) // or #ifdef DEBUG
    // Debug code
#endif

Pour éviter d'utiliser partout dans le code source:

#if defined(DEBUG)
    My_Debug_function(some_variable)
#endif

Vous pouvez faire dans l'en-tête

#if !defined(DEBUG) // or #ifndef DEBUG
# define My_Debug_function(some_variable) do { static_cast<void>(some_variable); } while (false)  /* Do nothing */
#endif

Et utilisez donc My_Debug_function presque normalement.

2
Jarod42