Plusieurs explications. Le premier est général, le second est spécifique aux macros de préprocesseur C avec des paramètres:
Contrôle de flux
J'ai vu cela utilisé dans du code C brut. Fondamentalement, c'est une version plus sûre de goto, car vous pouvez en sortir et toute la mémoire est nettoyée correctement.
Pourquoi quelque chose gotocomme ça serait bien? Eh bien, si vous avez du code où à peu près chaque ligne peut retourner une erreur, mais vous devez réagir à tous de la même façon (par exemple , en remettant l'erreur à votre correspondant après le nettoyage), il est généralement plus facile à lire pour éviter un if( error ) { /* cleanup and error string generation and return here */ }comme cela évite la duplication du code de nettoyage.
Cependant, en C ++, vous avez des exceptions + RAII exactement dans ce but, donc je considérerais que c'est un mauvais style de codage.
Vérification des points-virgules
Si vous oubliez le point-virgule après un appel de macro de type fonction, les arguments peuvent se contracter d'une manière indésirable et se compiler dans une syntaxe valide. Imaginez la macro
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
C'est accidentellement appelé comme
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
Le "else" sera considéré comme étant associé au gDebugModeOn, alors quand fooc'est le cas false, l'inverse exact de ce qui était prévu se produira.
Fournir une portée pour les variables temporaires.
Puisque le do / while a des accolades, les variables temporaires ont une portée clairement définie à laquelle elles ne peuvent pas échapper.
Éviter les avertissements de type "point-virgule éventuellement indésirable"
Certaines macros ne sont activées que dans les versions de débogage. Vous les définissez comme:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
Maintenant, si vous utilisez ceci dans une version de version à l'intérieur d'un conditionnel, il se compile en
if( foo )
;
De nombreux compilateurs voient cela comme
if( foo );
Ce qui est souvent écrit accidentellement. Vous recevez donc un avertissement. Le do {} while (false) cache cela au compilateur et est accepté par lui comme une indication que vous ne voulez vraiment rien faire ici.
Éviter la capture de lignes par des conditions
Macro de l'exemple précédent:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
Maintenant, dans une version de débogage, puisque nous incluons aussi habituellement le point-virgule, cela compile très bien. Cependant, dans la version de version, cela se transforme soudainement en:
if( foo )
doSomething();
Ou plus clairement formaté
if( foo )
doSomething();
Ce qui n'est pas du tout ce qui était prévu. L'ajout d'un do {...} while (false) autour de la macro transforme le point-virgule manquant en une erreur de compilation.
Qu'est-ce que cela signifie pour l'OP?
En général, vous souhaitez utiliser des exceptions en C ++ pour la gestion des erreurs et des modèles au lieu de macros. Cependant, dans le cas très rare où vous avez encore besoin de macros (par exemple, lorsque vous générez des noms de classe en utilisant le collage de jetons) ou que vous êtes limité au C pur, c'est un modèle utile.