web-dev-qa-db-fra.com

faire {...} pendant (0) - à quoi sert-il?

Duplicate possible:
Pourquoi y a-t-il parfois des instructions sans signification dans les macros C/C++?// Et/si/else?

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 sauts (au lieu de gotos.)

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

305
gilm

C'est la seule construction en C que vous pouvez utiliser pour #define une opération multi-déclarations, placer un point-virgule après et continuer à être utilisé dans une instruction if. Un exemple pourrait aider:

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

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

Même utiliser des accolades n'aide pas:

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

Utiliser 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
    ....
457
Greg Hewgill

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

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

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

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

et vous faites

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

alors cela se développe à

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

Notez que le second appel (bar (n)) ne fait plus partie de l'instruction if.

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

74
Martin v. Löwis

Il est intéressant de noter la situation suivante dans laquelle la boucle do {} while (0) ne fonctionnera pas :

Si vous voulez une macro semblable à une fonction qui renvoie une valeur, vous aurez besoin de expression de déclaration : ({stmt; stmt;}) à la place de {} tandis que (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