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