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


Posible Duplicado:
¿Por qué hay a veces sentencias do/while y if/else sin sentido en macros de C / C++?

He estado viendo esa expresión por más de 10 años. He estado tratando de pensar para qué sirve. Dado que lo veo principalmente en # defines, asumo que es bueno para la declaración de variables de ámbito interno y para usar breaks (en lugar de gotos.)

¿Es bueno para algo más? ¿Lo usas?

 271
Author: Community, 2008-11-03

5 answers

Es la única construcción en C que puede usar para #define una operación de declaración múltiple, poner un punto y coma después, y aún usar dentro de una instrucción if. Un ejemplo podría ayudar:

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

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

Incluso usar frenos no ayuda:

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

Usar esto en una instrucción if requeriría que omitas el punto y coma, que es contraintuitivo:

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

Si defines FOO así:

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

Entonces lo siguiente es sintácticamente correcto:

if (condition)
    FOO(x);
else
    ....
 403
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-03 09:24:33

Es una forma de simplificar la comprobación de errores y evitar si anidados profundamente. Por ejemplo:

do {
  // do something
  if (error) {
    break;
  }
  // do something else
  if (error) {
    break;
  }
  // etc..
} while (0);
 89
Author: Jere.Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 23:48:54

Ayuda a agrupar varias sentencias en una sola, para que una macro similar a una función pueda usarse realmente como una función. Supongamos que tiene

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

Y lo haces

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 (bar(n)) ya no forma parte de la instrucción if.

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

 64
Author: Martin v. Löwis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 21:39:51

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

Si desea una macro similar a una función que devuelva un valor, entonces necesitará una expresión de instrucción : ({stmt; stmt;}) en lugar de hacer {} 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
Author: ubuntu-fanboy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-07 16:34:43

Genéricamente, do/while es bueno para cualquier tipo de construcción de bucle donde uno debe ejecutar el bucle al menos una vez. Es posible emular este tipo de bucle a través de un while recto o incluso un for bucle, pero a menudo el resultado es un poco menos elegante. Admito que las aplicaciones específicas de este patrón son bastante raras, pero existen. Uno que me viene a la mente es una aplicación de consola basada en menús:

do {
    char c = read_input();

    process_input(c);
} while (c != 'Q');
 -4
Author: Daniel Spiewak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 21:39:02