do { ... } while (0) - à quoi sert-il? [dupliquer]

Doublon Possible:
Pourquoi y a-t-il parfois des instructions do/while et if/else sans signification dans les macros c / c++?

Je vois cette expression depuis plus de 10 ans maintenant. J'ai essayé de penser à ce que c'est bon pour. Comme je le vois principalement dans #defines, je suppose que c'est bon pour la déclaration de variable de portée interne et pour l'utilisation de pauses (au lieu de gotos.)

Est-ce bon pour autre chose? L'utilisez-vous?

271
demandé sur Community 2008-11-03 00:36:17

5 réponses

C'est la seule construction en C que vous pouvez utiliser pour #define un instructions multiples fonctionnement, mettre un point-virgule après, et toujours dans un if déclaration. Un exemple pourrait aider:

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

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

, Même en utilisant des accolades n'aide pas:

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

L'utilisation de ceci dans une instruction if nécessiterait que vous omettiez le point-virgule, Ce Qui est contre-intuitif:

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

Si vous définissez FOO comme ceci:

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

Alors ce qui suit est syntaxiquement correct:

if (condition)
    FOO(x);
else
    ....
403
répondu Greg Hewgill 2008-11-03 09:24:33

C'est un moyen de simplifier la vérification des erreurs et d'éviter les if imbriqués en profondeur. par exemple:

do {
  // do something
  if (error) {
    break;
  }
  // do something else
  if (error) {
    break;
  }
  // etc..
} while (0);
89
répondu Jere.Jones 2008-11-02 23:48:54

Cela aide à regrouper plusieurs instructions en une seule, de sorte qu'une macro de type Fonction peut réellement être utilisée en tant que fonction. Supposons que vous ayez

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

Et vous le faites

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

Ensuite, cela se développe à

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

Notez que le deuxième appel(bar (N)) ne fait plus partie de l'instruction if.

Enveloppez les deux dans do {} while (0), et vous pouvez également utiliser la macro dans une instruction if.

64
répondu Martin v. Löwis 2008-11-02 21:39:51

Il est intéressant de noter la situation suivante où la boucle do {} while (0) ne fonctionnera pas pour vous:

Si vous voulez une macro de type fonction qui renvoie une valeur, vous aurez besoin d'une expression d'instruction : ({stmt; stmt;}) au lieu de 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;
}
17
répondu ubuntu-fanboy 2011-01-07 16:34:43

Génériquement, do/while est bon pour toute sorte de boucle de construire où l'on doit exécuter la boucle , au moins une fois. Il est possible d'imiter ce genre de boucle à travers une boucle droite while ou même une boucle for, mais souvent le résultat est un peu moins élégant. J'admettrai que les applications spécifiques de ce modèle sont assez rares, mais elles existent. Celui qui vient à l'esprit est une application de console basée sur le menu:

do {
    char c = read_input();

    process_input(c);
} while (c != 'Q');
-4
répondu Daniel Spiewak 2008-11-02 21:39:02