web-dev-qa-db-fra.com

C macro multiligne: bloc do / while (0) vs scope

Doublons possibles:
Quelle est l’utilisation de do tandis que (0) lorsque nous définissons une macro?
Pourquoi y a-t-il parfois des instructions sans signification dans les macros C/C++?// Et/si/else?
fait {…} tandis que (0) à quoi sert-il?

J'ai vu des macros C multilignes enveloppées dans une boucle do/while (0) comme:

 # définir FOO\
 faire {\ 
 do_stuff_here\
 do_more_stuff\
} tandis que (0) 

Quels sont les avantages (le cas échéant) d’écrire le code de cette manière par opposition à l’utilisation d’un bloc de base:

 # définir FOO\
 {\ 
 do_stuff_here\
 do_more_stuff\
} 
170
krasnaya

http://bytes.com/groups/c/219859-do-while-0-macro-substitutions

Andrey Tarasevich:

L’idée même de l’utilisation de la version 'do/while' est de créer une macro qui deviendra une instruction normale et non une instruction composée. Ceci est fait afin de rendre uniforme l'utilisation de macros de style fonction avec l'utilisation de fonctions ordinaires dans tous les contextes.

Considérez l'esquisse de code suivante

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

où 'foo' et 'bar' sont des fonctions ordinaires. Maintenant, imaginez que vous souhaitiez remplacer la fonction 'foo' par une macro de la nature ci-dessus

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

Désormais, si votre macro est définie conformément à la deuxième approche (uniquement '{' et '}'), le code ne sera plus compilé, car la branche 'true' de 'if' est maintenant représentée par une instruction composée. Et quand tu mets un ';' après cette instruction composée, vous avez terminé l’instruction entière "if", orphelinant ainsi la branche "else" (d’où l’erreur de compilation).

Une façon de corriger ce problème est 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 la plus élégante consiste à s’assurer que la macro se développe en déclaration ordinaire et non en 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);

va compiler sans aucun problème.

Cependant, notez la différence petite mais importante entre ma définition de CALL_FUNCS Et la première version de votre message. Je n'ai pas mis un ; Après } while (0). Mettre un ; À la fin de cette définition annulerait immédiatement l'utilisation de 'do/while' et rendrait cette macro assez équivalente à la version de l'instruction composée.

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

251
caskey