do {...} while (0): ¿para qué sirve? [duplicar]

Resuelto gilm asked hace 16 años • 5 respuestas

He estado viendo esa expresión desde hace más de 10 años. He estado tratando de pensar para qué sirve. Como lo veo principalmente en #defines, supongo que es bueno para la declaración de variables de alcance interno y para usar saltos (en lugar de gotos).

¿Sirve para algo más? ¿Lo usas?

gilm avatar Nov 03 '08 04:11 gilm
Aceptado

Es la única construcción en C que puede usar para #defineuna operación de múltiples declaraciones, poner un punto y coma después y seguir usándola dentro de una ifdeclaración. Un ejemplo podría ayudar:

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

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

Incluso el uso de frenillos no ayuda:

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

Usar esto en una ifdeclaración requeriría omitir el punto y coma, lo cual es contrario a la intuición:

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

Si define FOO así:

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

entonces lo siguiente es sintácticamente correcto:

if (condition)
    FOO(x);
else
    ....
Greg Hewgill avatar Nov 02 '2008 21:11 Greg Hewgill

Es una forma de simplificar la verificación de errores y evitar if anidados profundos. Por ejemplo:

do {
  // do something
  if (error) {
    break;
  }
  // do something else
  if (error) {
    break;
  }
  // etc..
} while (0);
Jere.Jones avatar Nov 02 '2008 21:11 Jere.Jones

Es útil agrupar varias declaraciones en una sola para que una macro similar a una función pueda usarse como una función. Supongamos que tienes:

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

y lo hace:

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

entonces esto se expande a:

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

Observe que la segunda llamada ya bar(n)no forma parte de la ifdeclaración.

Envuelva ambos en do { } while(0)y también puede usar la macro en una ifdeclaración.

Martin v. Löwis avatar Nov 02 '2008 21:11 Martin v. Löwis

Es interesante observar la siguiente situación en la que el bucle do {} while (0) no funcionará:

Si desea una macro similar a una función que devuelva un valor, necesitará una expresión de declaración : ({stmt; stmt;}) en lugar 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;
}
ubuntu-fanboy avatar Jan 07 '2011 16:01 ubuntu-fanboy