do { ... } while (0) - do czego to służy? [duplikat]
Widzę to wyrażenie od ponad 10 lat. Zastanawiam się, do czego to służy. Ponieważ widzę to głównie w # defines, zakładam, że jest dobre dla deklaracji zmiennej Inner scope i dla używania przerw (zamiast gotos.) Czy jest dobry na coś jeszcze? Używasz go?Możliwy duplikat:
Dlaczego w makrach C/C++ występują czasami bezsensowne wyrażenia do/while I if/else?
5 answers
Jest to jedyna konstrukcja w C, której możesz użyć do #define
operacji wielostanowiskowej, umieścić średnik PO i nadal używać w instrukcji if
. Przykład może pomóc:
#define FOO(x) foo(x); bar(x)
if (condition)
FOO(x);
else // syntax error here
...;
Nawet używanie szelek nie pomaga:
#define FOO(x) { foo(x); bar(x); }
Użycie tego wyrażenia w if
wymagałoby pominięcia średnika, który jest przeciwny dointuitywny:
if (condition)
FOO(x)
else
...
Jeśli zdefiniujesz FOO tak:
#define FOO(x) do { foo(x); bar(x); } while (0)
Wtedy następująca jest poprawna składniowo:
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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-03 09:24:33
Jest to sposób na uproszczenie sprawdzania błędów i unikanie głębokiego zagnieżdżania if. na przykład:
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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-02 23:48:54
Pomaga grupować wiele poleceń w jedno, tak aby makro podobne do funkcji mogło być użyte jako funkcja. Załóżmy, że masz
#define FOO(n) foo(n);bar(n)
I robisz
void foobar(int n){
if (n)
FOO(n);
}
Następnie to rozszerza się do
void foobar(int n){
if (n)
foo(n);bar(n);
}
Zauważ, że drugie wywołanie (bar (n)) nie jest już częścią instrukcji if.
Zawiń oba w do{}while(0), a możesz również użyć makra w instrukcji if.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-02 21:39:51
Warto zwrócić uwagę na następującą sytuację, w której pętla do {} while (0) nie będzie działać dla Ciebie:
Jeśli chcesz mieć makro podobne do funkcji, które zwraca wartość, będziesz potrzebował wyrażenia instrukcji : ({stmt; stmt;}) zamiast 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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-07 16:34:43
Ogólnie, do
/while
jest dobre dla każdego rodzaju konstrukcji pętli, gdzie należy wykonać pętlę przynajmniej raz. Możliwe jest naśladowanie tego rodzaju pętli poprzez prostą while
lub nawet pętlę for
, ale często wynik jest nieco mniej elegancki. Przyznam, że konkretne zastosowania tego wzoru są dość rzadkie, ale istnieją. Jednym, który przychodzi na myśl, jest aplikacja konsolowa oparta na menu:
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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-02 21:39:02