it-swarm.com.de

mache {...} während (0) - wofür ist es gut?

Mögliches Duplikat:
Warum gibt es manchmal sinnlose do/while- und if/else-Anweisungen in C/C++ - Makros?

Ich habe diesen Ausdruck seit über 10 Jahren gesehen. Ich habe versucht zu überlegen, wofür es gut ist. Da ich es meistens in #defines sehe, gehe ich davon aus, dass es für die Deklaration von Variablen im inneren Gültigkeitsbereich und für die Verwendung von Pausen (anstelle von gotos) gut ist.

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

305
gilm

Es ist das einzige Konstrukt in C, mit dem Sie #define eine Multistatement-Operation, setzen Sie ein Semikolon nach und verwenden Sie sie weiterhin in einer if -Anweisung. Ein Beispiel könnte helfen:

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

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

Auch die Verwendung von Zahnspangen hilft nicht:

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

Wenn Sie dies in einer if -Anweisung verwenden, müssen Sie das Semikolon auslassen. Dies ist nicht intuitiv:

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

Wenn Sie FOO wie folgt definieren:

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

dann ist das folgende syntaktisch korrekt:

if (condition)
    FOO(x);
else
    ....
457
Greg Hewgill

Dies 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);
103
Jere.Jones

Es hilft, mehrere Anweisungen in einer einzigen zu gruppieren, 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 (Balken (n)) nicht mehr Teil der if-Anweisung ist.

Schließen Sie beide in do {} while (0) ein, und Sie können das Makro auch in einer if-Anweisung verwenden.

74

Es ist interessant, die folgende Situation zu beachten, in der die do {} while (0) -Schleife für Sie nicht funktioniert :

Wenn Sie ein funktionsähnliches Makro möchten, das einen Wert zurückgibt, benötigen Sie einen Anweisungsausdruck : ({stmt; stmt;}) anstelle von 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;
}
18
ubuntu-fanboy