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)?
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.
Pour définir une telle macro, vous pouvez
#define MY_CONTROL_MACRO
à votre code. Ou,MY_CONTROL_MACRO
à Project > Properties > C/C++ > Preprocessor > Preprocessor Definitions
. Ou,-DMY_CONTROL_MACRO
.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.
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
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.
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 ...
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?
De toute évidence, cette approche ne fonctionne que pour les instructions de débogage à l'intérieur des corps de méthode/fonction.
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.
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
Entourez votre code de test #ifdef DEBUG
.
#if DEBUG
....
#endif
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.