Was nützt do while(0), wenn wir ein Makro definieren? [duplicate]
Lesezeit: 3 Minuten
erstaunlichjxq
Mögliche Duplikate:
Do-While- und if-else-Anweisungen in C/C++-Makros
do { … } while (0) — wozu ist es gut?
Ich lese den Linux-Kernel und habe viele Makros wie diese gefunden:
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
Warum verwenden sie dies, anstatt es einfach in einem {} zu definieren?
Sie können ihm ein Semikolon folgen lassen und es eher wie eine Funktion aussehen und verhalten. Es funktioniert dann auch mit if/else-Klauseln einwandfrei.
Ohne das while(0) würde Ihr obiger Code nicht funktionieren
if (doit)
INIT_LIST_HEAD(x);
else
displayError(x);
da das Semikolon nach dem Makro die Else-Klausel “fressen” würde und das obige nicht einmal kompilieren würde.
Aber die Frage des OP steht. Warum nicht einfach { (ptr)->next … } statt do { (ptr)->next … } while (0);?
– joshk0
29. Mai 2009 um 0:26 Uhr
Arno hat das erklärt. Es würde sich erweitern zu “{ (ptr)->next … };” also eine Anweisung gefolgt von einer zweiten Anweisung. Die If-Syntax lautet jedoch “if ( expression ) statement else statement” . Das else wäre keinem if zugeordnet, da Sie „if ( expression ) statement statement“ geschrieben hätten (eine „{ … }“- und eine „;“-Anweisung).
– Johannes Schaub – litb
29. Mai 2009 um 0:37 Uhr
Wie Amo sagte, ist es ein cleverer Trick, der es einem Makro ermöglicht sein eine C-Anweisung, die mit einem Semikolon enden muss. Dadurch verhält sich das Makro genau wie ein Funktionsaufruf, was den Aufbau und die Beendigung der Anweisung (mit ‘;’) betrifft.
– Edi
29. Mai 2009 um 1:53 Uhr
Beachten Sie jedoch, dass in diesem Fall alles völlig unnötig ist, da der Hauptteil des Makros viel sauberer geschrieben werden könnte als: (ptr)->next=(ptr)->prev=(ptr).
– Jerry Sarg
2. Dezember 2009 um 4:19 Uhr
@JoshK Die Schleife wird nur einmal ausgeführt, da while(0) eine falsche Bedingung ist. Ein optimierender Compiler wird sich jedoch davon befreien do {stat}while(0) & durch nur ersetzen stat weil es sowieso nur einmal passiert.
– Karim Manauil
5. September 2017 um 19:01 Uhr
Rodion
Es ermöglicht Ihnen, mehrere Anweisungen in einem Makro zu gruppieren.
Angenommen, Sie haben Folgendes getan:
if (foo)
INIT_LIST_HEAD(bar);
Wenn das Makro ohne das kapselnde do { … } while (0); definiert wurde, würde der obige Code zu erweitern
if (foo)
(bar)->next = (bar);
(bar)->prev = (bar);
Dies ist eindeutig nicht beabsichtigt, da nur die erste Anweisung ausgeführt wird, wenn foo gilt. Die zweite Anweisung würde unabhängig davon ausgeführt, ob foo gilt.