do { … } while (0) — wozu ist es gut? [duplicate]

Lesezeit: 7 Minuten

Benutzeravatar von gilm
vergoldet

Ich sehe diesen Ausdruck seit über 10 Jahren. Ich habe versucht zu überlegen, wozu es gut sein soll. Da ich es hauptsächlich in #defines sehe, gehe ich davon aus, dass es gut für die Deklaration von Variablen im inneren Bereich und für die Verwendung von Unterbrechungen (anstelle von Gotos) ist.

Ist es für irgendetwas anderes gut? Benutzt du es?

  • Schauen Sie sich diese Frage an.

    – Federico A. Ramponi

    2. November 2008 um 21:38 Uhr

  • Tatsächlich handelt es sich nicht um ein Duplikat, da die verknüpfte Frage/Antwort nicht spezifisch zu definieren ist. Es ist einfach, beide Antworten zu vergleichen, um festzustellen, dass es sich nicht um ein Duplikat handelt.

    – Weltuntergang

    18. Mai 2012 um 15:44 Uhr

  • Siehe “decrement_used_memory” von Redis, Zeile 53 https://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-forgithub.com/antirez/redis-tools/blob/master/zmalloc.c

    – noch

    9. Dezember 2012 um 21:57 Uhr

  • Das Duplikat ist mit der als mögliches Duplikat markierten Frage (erste Zeile des Beitrags), nicht mit der Frage von Federico A. Ramponi.

    – Etienne

    2. Mai 2013 um 8:52 Uhr

  • andere Varianten davon do { ... } while ((void)0, 0) Wird verwendet, um Compiler-Warnungen über “konstanten Zustand” stumm zu schalten.

    – Amro

    1. Januar 2016 um 0:56 Uhr

Benutzeravatar von Greg Hewgill
Greg Hewgill

Es ist das einzige Konstrukt in C, das Sie verwenden können #define B. eine Operation mit mehreren Anweisungen, setzen Sie ein Semikolon dahinter und verwenden Sie sie trotzdem innerhalb von an if Aussage. Ein Beispiel könnte helfen:

#define FOO(x) foo(x); bar(x)

if (condition)
    FOO(x);
else // syntax error here
    ...;

Auch die Verwendung von Klammern hilft nicht:

#define FOO(x) { foo(x); bar(x); }

Verwenden Sie dies in einem if -Anweisung erfordern, dass Sie das Semikolon weglassen, was kontraintuitiv ist:

if (condition)
    FOO(x)
else
    ...

Wenn Sie FOO so definieren:

#define FOO(x) do { foo(x); bar(x); } while (0)

dann ist syntaktisch korrekt:

if (condition)
    FOO(x);
else
    ....

  • Würde nicht #define FOO(x) if(true){ foo(x); bar(x); } else void(0) auch funktionieren, obwohl es viel hässlicher ist?

    – Adissak

    7. August 2013 um 22:39 Uhr


  • @ user10607: Ja, das funktioniert, wenn Ihre Makroerweiterungen eine Liste von sind Ausdrücke. Wenn Sie jedoch eine if oder while Innerhalb der Erweiterung funktioniert dieser Trick auch nicht.

    – Greg Hewgill

    3. November 2014 um 19:45 Uhr

  • Ich denke immer noch, dass dies HÄSSLICH und SLOPPY-Codierung ist und vermieden werden kann, wenn sie richtig codiert wird. Dies geht auf einige der C-Regeln des gesunden Menschenverstandes zurück, dass Sie IMMER Curlys in Ihren IF-Anweisungen verwenden, selbst wenn Sie nur EINE Operation nach dem IF haben. Das sollte Standard sein, IMVHO …

    – LarryF

    16. Juli 2015 um 20:37 Uhr

  • @LarryF: Das Problem ist, wenn Sie eine Header-Datei für die Verwendung durch andere schreiben, können Sie nicht auswählen, wie andere Personen Ihr Makro verwenden. Um unerwartete Überraschungen zu vermeiden, die Ihren Benutzern zugefügt werden, müssen Sie eine Technik wie die obige verwenden, damit sich Ihr Makro so verhält, wie sich jede andere C-Anweisung verhalten würde.

    – Greg Hewgill

    16. Juli 2015 um 23:39 Uhr

  • @AaronFranke weil {…}; besteht eigentlich aus zwei Anweisungen, dem Teil {…} und einer weiteren leeren Anweisung danach. mache {…} while(0); ist jedoch eine Aussage. Larry/Marco Wenn Benutzer FOO(a, b, c) schreiben, erwarten sie (sofern nicht ausdrücklich anders beabsichtigt), dass dies zu einem Ausdruck führt, ähnlich wie ein Aufruf einer void-zurückgebenden Funktion. Ihre ist eigentlich die schlampige Herangehensweise. Die Codestilkonvention Ihres Benutzers sollte Sie nicht interessieren.

    – jonil

    26. Juni 2020 um 10:06 Uhr

Benutzeravatar von Jere.Jones
Jere.Jones

Es ist eine Möglichkeit, die Fehlerprüfung zu vereinfachen und tief verschachtelte ifs zu vermeiden. Zum Beispiel:

do {
  // do something
  if (error) {
    break;
  }
  // do something else
  if (error) {
    break;
  }
  // etc..
} while (0);

  • ähm, berücksichtige es in einer Methode und verwende eine frühe Rückkehr.

    – Dustin Getz

    2. November 2008 um 23:35 Uhr

  • oder … verwenden Sie einfach do { } while(0).

    – Nickf

    2. November 2008 um 23:48 Uhr

  • Oder verwenden goto. Nein im Ernst, if (error) goto error; und ein error: ... Gegen Ende scheint es mir eine sauberere Version zu sein, die dasselbe erreicht.

    – Glühwürmchen

    23. April 2014 um 17:46 Uhr

  • @WChargin: Der Code “Goto Fail” in dem von Ihnen verlinkten Artikel wäre auch mit einem “Break” fehlgeschlagen. Jemand hat dort gerade eine Zeile dupliziert. Es war nicht Gotos Schuld.

    – Nicolo M.

    15. Juni 2014 um 11:15 Uhr

  • @NicolM. “Zugegeben, goto war nicht der Fehler, was es sogar noch lustiger macht”

    – Waschen

    15. Juni 2014 um 17:36 Uhr

Benutzeravatar von Martin v. Löwis
Martin v. Löwen

Es ist hilfreich, mehrere Anweisungen zu einer einzigen zusammenzufassen, sodass ein funktionsähnliches Makro tatsächlich als Funktion verwendet werden kann. Angenommen, Sie haben:

#define FOO(n)   foo(n);bar(n)

und du machst:

void foobar(int n) {
  if (n)
     FOO(n);
}

dann erweitert sich dies zu:

void foobar(int n) {
  if (n)
     foo(n);bar(n);
}

Beachten Sie, dass der zweite Aufruf bar(n) ist nicht Teil der if Aussage nicht mehr.

Beides einwickeln do { } while(0)und Sie können das Makro auch in einer verwenden if Aussage.

  • Sehr klare Antwort. +1

    – Anirudh Ramanathan

    23. Juni 2015 um 18:57 Uhr

  • Einwandfrei verstanden. 😉

    – Wer bin ich

    6. Juli 2016 um 6:04 Uhr

  • Warum nicht einfach Klammern drum herum? #define FOO(n) {foo(n);bar(n)}

    – Endolith

    27. August 2021 um 19:21 Uhr


  • @endolith Weil #define FOO(n) {foo(n);bar(n)} erweitern würde {foo(n);bar(n)}. Beachten Sie, dass danach kein Semikolon steht bar(n).

    – John

    19. Oktober 2021 um 12:37 Uhr


Es ist interessant, die folgende Situation zu bemerken, in der die Schleife do {} while (0) ausgeführt wird Gewohnheit Arbeite für dich:

Wenn Sie ein funktionsähnliches Makro wünschen, das einen Wert zurückgibt, benötigen Sie eine Aussage Ausdruck: ({stmt; stmt;}) statt do {} while(0):


#include <stdio.h>

#define log_to_string1(str, fmt, arg...) \
    do { \
        sprintf(str, "%s: " fmt, "myprog", ##arg); \
    } while (0)

#define log_to_string2(str, fmt, arg...) \
    ({ \
        sprintf(str, "%s: " fmt, "myprog", ##arg); \
    })

int main() {
        char buf[1000];
        int n = 0;

        log_to_string1(buf, "%s\n", "No assignment, OK");

        n += log_to_string1(buf + n, "%s\n", "NOT OK: gcc: error: expected expression before 'do'");

        n += log_to_string2(buf + n, "%s\n", "This fixes it");
        n += log_to_string2(buf + n, "%s\n", "Assignment worked!");
        printf("%s", buf);
        return 0;
}

Allgemein, do/while ist gut für jede Art von Schleifenkonstruktion, bei der man die Schleife ausführen muss wenigstens einmal. Es ist möglich, diese Art des Schleifens durch eine Gerade zu emulieren while oder sogar ein for Schleife, aber oft ist das Ergebnis etwas weniger elegant. Ich gebe zu, dass spezifische Anwendungen dieses Musters ziemlich selten sind, aber es gibt sie. Eine, die mir in den Sinn kommt, ist eine menübasierte Konsolenanwendung:

do {
    char c = read_input();

    process_input(c);
} while (c != 'Q');

  • Es ist auch in C# verfügbar, das keine Makros hat. Ich bin mir nicht sicher, warum jemand diese Antwort abgelehnt hat, aber ich sehe sie als die fast richtige Antwort, außer dass sie die explizite “0” in der while-Bedingung übersehen hat. Bitte, Leute, wenn Sie die Antwort von jemandem ablehnen, kommentieren Sie sie bitte.

    – Jon Davis

    2. November 2008 um 22:36 Uhr

  • Ich war nicht derjenige, der negativ gestimmt hat; Die Frage ist jedoch sehr spezifisch und die Antwort ist im Allgemeinen wahr, aber außerhalb des Kontexts.

    – zot

    2. November 2008 um 23:04 Uhr

  • Die Aussage ist richtig, aber sie ist aus dem Zusammenhang gerissen.

    – Nadeem Khan

    18. März 2019 um 10:08 Uhr

  • Es ist auch in C# verfügbar, das keine Makros hat. Ich bin mir nicht sicher, warum jemand diese Antwort abgelehnt hat, aber ich sehe sie als die fast richtige Antwort, außer dass sie die explizite “0” in der while-Bedingung übersehen hat. Bitte, Leute, wenn Sie die Antwort von jemandem ablehnen, kommentieren Sie sie bitte.

    – Jon Davis

    2. November 2008 um 22:36 Uhr

  • Ich war nicht derjenige, der negativ gestimmt hat; Die Frage ist jedoch sehr spezifisch und die Antwort ist im Allgemeinen wahr, aber außerhalb des Kontexts.

    – zot

    2. November 2008 um 23:04 Uhr

  • Die Aussage ist richtig, aber sie ist aus dem Zusammenhang gerissen.

    – Nadeem Khan

    18. März 2019 um 10:08 Uhr

1427690cookie-checkdo { … } while (0) — wozu ist es gut? [duplicate]

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

Privacy policy