226 votes

Macro C multi-lignes : do/while(0) vs bloc d'étendue

Duplicatas possibles :
Quelle est l'utilité de do while(0) lorsque l'on définit une macro ?
Pourquoi y a-t-il parfois des instructions do/while et if/else sans signification dans les macros C/C++ ?
do { } while (0) à quoi cela sert-il ?

J'ai vu des macros C de plusieurs lignes qui sont enveloppées dans une boucle do/while(0), par exemple :

#define FOO \\
  do { \\
    do\_stuff\_here \\
    do\_more\_stuff \\
  } while (0)

Quels sont les avantages (s'il y en a) d'écrire le code de cette façon plutôt que d'utiliser un bloc de base ?

#define FOO \\
  { \\
    do\_stuff\_here \\
    do\_more\_stuff \\
  }

0 votes

En fait, il existe un autre moyen de faire les choses correctement. ({...}) peut faire la même chose que do {} while(0). Réf : bruceblinn.com/linuxinfo/DoWhile.html

2 votes

@wuxb : le ({...}) construct est une extension de GCC et n'est pas supportée par le standard C de l'ISO.

334voto

caskey Points 5581

Andrey Tarasevich fournit l'explication suivante :

  1. Sur Google Groupes
  2. Sur bytes.com

[Des changements mineurs ont été apportés au formatage. Les annotations entre parenthèses ont été ajoutées entre crochets. [] ].

L'idée générale de l'utilisation de la version 'do/while' est de créer une macro qui va qui se développera en une instruction normale, et non en une instruction composée. Ceci est afin d'uniformiser l'utilisation des macros de type fonction avec l'utilisation des l'utilisation de fonctions ordinaires dans tous les contextes.

Considérons l'esquisse de code suivante :

if (<condition>)
  foo(a);
else
  bar(a);

donde foo y bar sont des fonctions ordinaires. Imaginez maintenant que vous souhaitez souhaitez remplacer la fonction foo avec une macro de la nature ci-dessus [nommée CALL_FUNCS ] :

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

Maintenant, si votre macro est définie selon la deuxième approche (juste { y } ) le code ne compilera plus, car la branche 'true' (vraie) de if est maintenant représentée par une déclaration composée. Et lorsque vous mettez un ; après cette déclaration composée, vous avez terminé l'ensemble if , ce qui rend orphelin le else (d'où l'erreur de compilation).

Une façon de corriger ce problème est de se rappeler de ne pas mettre ; après macro "invocations" :

if (<condition>)
  CALL_FUNCS(a)
else
  bar(a);

Cela compilera et fonctionnera comme prévu, mais ce n'est pas uniforme. La solution plus élégante solution la plus élégante est de s'assurer que la macro se développe dans une ordinaire, et non dans une déclaration composée. Une façon d'y parvenir est de définir la macro comme suit :

#define CALL_FUNCS(x) \
do { \
  func1(x); \
  func2(x); \
  func3(x); \
} while (0)

Maintenant ce code :

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

compilera sans problème.

Cependant, notez la petite mais importante différence entre ma définition de CALL_FUNCS et la première version dans votre message. Je n'ai pas mis de ; après } while (0) . Mettre un ; à la fin de cette définition l'intérêt d'utiliser 'do/while' et rendrait cette macro pratiquement cette macro est pratiquement équivalente à la version de l'instruction composée.

Je ne sais pas pourquoi l'auteur du code que vous avez cité dans votre message original message original a mis ceci ; après while (0) . Sous cette forme, les deux variantes sont équivalentes. L'idée derrière l'utilisation de la version 'do/while' est de ne pas d'inclure cette dernière ; dans la macro (pour les raisons que j'ai expliquées ci-dessus).

62 votes

Le message original a été fait par moi en comp.lang.c . bytes.com s'approprie apparemment le contenu de comp.lang.c sans faire aucune référence à la source.

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