133 votes

Quelle est l'utilité de do while(0) lorsque l'on définit une macro ?

Duplicatas possibles :
Instructions Do-While et if-else dans les macros C/C++.
do { } while (0) - à quoi cela sert-il ?

Je suis en train de lire le noyau linux et j'ai trouvé beaucoup de macros comme celle-ci :

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

Pourquoi utilise-t-on cela plutôt que de le définir simplement dans un {} ?

147voto

SPWorley Points 5439

Vous pouvez le faire suivre d'un point-virgule et le faire ressembler et agir davantage comme une fonction. Cela fonctionne aussi correctement avec les clauses if/else.

Sans le while(0), votre code ci-dessus ne fonctionnerait pas avec

if (doit) 
   INIT_LIST_HEAD(x);
 else 
   displayError(x);

car le point-virgule après la macro "mangerait" la clause else, et la phrase ci-dessus ne serait même pas compilée.

7 votes

Mais la question de l'OP reste inchangée. Pourquoi ne pas simplement { (ptr)->suivant ... } au lieu de do { (ptr)->suivant ... } while (0); ?

29 votes

Arno l'a expliqué. Il se développerait en "{ (ptr)->suivant ... } ;" donc, une déclaration suivie d'une seconde déclaration. La syntaxe de If est cependant "if ( expression ) statement else statement" . Le else ne serait pas associé à un if, puisque vous auriez écrit "if ( expression ) statement statement" (une instruction "{ ... }" et une instruction " ;").

3 votes

Comme l'a dit Amo, c'est une astuce qui permet à une macro de être une instruction C qui doit se terminer par un point-virgule. Elle fait en sorte que la macro se comporte exactement comme un appel de fonction, en ce qui concerne la construction et la fin de l'instruction (avec ';').

44voto

rodion Points 2431

Elle vous permet de regrouper plusieurs déclarations dans une seule macro.

Supposons que vous ayez fait quelque chose comme :

if (foo) 
    INIT_LIST_HEAD(bar);

Si la macro était définie sans l'encapsulation do { ... } while (0) ;, le code ci-dessus se développerait en

if (foo)
    (bar)->next = (bar);
    (bar)->prev = (bar);

Ce n'est clairement pas ce qui était prévu, car seule la première instruction sera exécutée si foo tient. La deuxième instruction sera exécutée indépendamment de la présence de foo.

Edit : Plus d'explications à http://c-faq.com/cpp/multistmt.html y http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Swallowing-the-Semicolon.html#Swallowing-the-Semicolon

10 votes

Cela n'explique pas la partie do while(0) de la macro, mais seulement l'utilisation des accolades {}.

0 votes

La partie do {} while (0) est expliquée dans le post dont celui-ci fait double emploi.

1 votes

SPWorley, adobriyan : En fait, il semble que l'auteur de ce billet ait ajouté des liens expliquant le do {} while (0).

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