Mehrzeiliges C-Makro: do/while(0) vs Scope-Block [duplicate]

Lesezeit: 3 Minuten

Benutzeravatar von krasnaya
krasnaja

Mögliche Duplikate:

Was nützt do while(0), wenn wir ein Makro definieren?
Warum gibt es in C/C++-Makros manchmal bedeutungslose do/while- und if/else-Anweisungen?
mache { … } während (0) wozu ist es gut?

Ich habe einige mehrzeilige C-Makros gesehen, die in eine do/while(0)-Schleife eingeschlossen sind:

#define FOO \
  do { \
    do_stuff_here \
    do_more_stuff \
  } while (0)

Was sind die Vorteile (falls vorhanden) des Schreibens des Codes auf diese Weise im Gegensatz zur Verwendung eines einfachen Blocks:

#define FOO \
  { \
    do_stuff_here \
    do_more_stuff \
  }

  • Duplikate: stackoverflow.com/questions/923822 und stackoverflow.com/questions/154136 und stackoverflow.com/questions/257418

    – etw

    1. Juli 2009 um 4:19 Uhr

  • Eigentlich gibt es einen anderen Weg, die Dinge richtig zu machen. ({…}) kann dasselbe tun wie {} while(0). Ref: bruceblinn.com/linuxinfo/DoWhile.html

    – wuxb

    3. August 2016 um 19:51 Uhr


  • @wuxb: die ({...}) construct ist eine GCC-Erweiterung und wird vom ISO-Standard C nicht unterstützt.

    – Nate Eldredge

    3. Dezember 2020 um 23:43 Uhr


  • Dies ist auch eine von CERT empfohlene Vorgehensweise: wiki.sei.cmu.edu/confluence/display/c/…

    – JVApen

    7. August 2021 um 10:10 Uhr

Caskeys Benutzeravatar
kaskey

Andrey Tarasevich liefert die folgende Erklärung:

  1. Auf Google Groups
  2. Auf bytes.com

[Minor changes to formatting made. Parenthetical annotations added in square brackets []].

Die ganze Idee der Verwendung der ‘do/while’-Version besteht darin, ein Makro zu erstellen, das zu einer regulären Anweisung erweitert wird, nicht zu einer zusammengesetzten Anweisung. Dies geschieht, um die Verwendung von Makros im Funktionsstil mit der Verwendung gewöhnlicher Funktionen in allen Kontexten einheitlich zu machen.

Betrachten Sie die folgende Codeskizze:

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

wo foo und bar sind gewöhnliche Funktionen. Stellen Sie sich nun vor, Sie möchten eine Funktion ersetzen foo mit einem Makro der oben genannten Art [named CALL_FUNCS]:

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

Wenn Ihr Makro nun gemäß dem zweiten Ansatz definiert ist (nur { und }) wird der Code nicht mehr kompiliert, da der „wahre“ Zweig von if wird jetzt durch eine zusammengesetzte Anweisung dargestellt. Und wenn Sie a setzen ; Nach dieser zusammengesetzten Anweisung haben Sie das Ganze beendet if
Aussage und verwaiste damit die else Zweig (daher der Kompilierungsfehler).

Eine Möglichkeit, dieses Problem zu beheben, besteht darin, daran zu denken, nicht zu setzen ; nach Makro-“Aufrufen”:

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

Dies wird wie erwartet kompiliert und funktionieren, aber das ist nicht einheitlich. Die elegantere Lösung besteht darin, dafür zu sorgen, dass das Makro zu einer regulären Anweisung erweitert wird, nicht zu einer zusammengesetzten. Eine Möglichkeit, dies zu erreichen, besteht darin, das Makro wie folgt zu definieren:

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

Jetzt dieser Code:

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

lässt sich ohne Probleme kompilieren.

Beachten Sie jedoch den kleinen, aber wichtigen Unterschied zwischen meiner Definition von CALL_FUNCS und die erste Version in Ihrer Nachricht. Ich habe kein gesetzt
; nach } while (0). Ein setzen ; am Ende dieser Definition würde sofort den gesamten Sinn der Verwendung von ‘do/while’ zunichte machen und dieses Makro ziemlich äquivalent zur Version der zusammengesetzten Anweisung machen.

Ich weiß nicht, warum der Autor des Codes, den Sie in Ihrer ursprünglichen Nachricht zitiert haben, dies geschrieben hat ; nach while (0). In dieser Form sind beide Varianten gleichwertig. Die ganze Idee hinter der Verwendung der ‘do/while’-Version besteht darin, dieses Finale nicht einzubeziehen ; in das Makro (aus den Gründen, die ich oben erklärt habe).

  • Der ursprüngliche Beitrag wurde von mir in erstellt comp.lang.c. bytes.com anscheinend “aneignet” sich den Inhalt von comp.lang.c ohne Quellenangabe.

    – AnT steht zu Russland

    23. Oktober 2009 um 6:30 Uhr

1425920cookie-checkMehrzeiliges C-Makro: do/while(0) vs Scope-Block [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy