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?
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
....
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);
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.
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;
}
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');