Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

macro do { } while(0)

6 réponses
Avatar
Patrick Lamaizière
'jour,

Quel est l'intérêt profond de déclarer des macros en do { } while (0) ?

Par exemple dans l'idée:

#define PRINT(x) do { \
printf(x); \
} while (0)

Merci.

6 réponses

Avatar
Michel Decima
Patrick Lamaizière a écrit :
'jour,

Quel est l'intérêt profond de déclarer des macros en do { } while (0) ?

Par exemple dans l'idée:

#define PRINT(x) do {
printf(x);
} while (0)



Eviter les problemes subtils lorsque la macro est appellee
dans un if/else, sans accolades :

void foo() { printf( "foo" ) ; }
void bar() { printf( "bar" } ; }

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

int main( int argc, char** argv )
{
if ( argc > 1 ) FOOBAR() ;
return 0 ;
}

Regarde le comportement avec et sans le do/while (et c'est encore
plus drole si on rajoute un else)
Avatar
Pierre Maurette
Michel Decima, le 24/09/2008 a écrit :
Patrick Lamaizière a écrit :
'jour,

Quel est l'intérêt profond de déclarer des macros en do { } while (0) ?

Par exemple dans l'idée:

#define PRINT(x) do {
printf(x);
} while (0)



Eviter les problemes subtils lorsque la macro est appellee
dans un if/else, sans accolades :

void foo() { printf( "foo" ) ; }
void bar() { printf( "bar" } ; }

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

int main( int argc, char** argv )
{
if ( argc > 1 ) FOOBAR() ;
return 0 ;
}

Regarde le comportement avec et sans le do/while (et c'est encore
plus drole si on rajoute un else)



Pourquoi pas simplement:
#define FOOBAR() {foo(); bar();}
?

--
Pierre Maurette
Avatar
Michel Decima
Pierre Maurette a écrit :
Michel Decima, le 24/09/2008 a écrit :
Patrick Lamaizière a écrit :
'jour,

Quel est l'intérêt profond de déclarer des macros en do { } while (0) ?

Par exemple dans l'idée:

#define PRINT(x) do {
printf(x);
} while (0)



Eviter les problemes subtils lorsque la macro est appellee
dans un if/else, sans accolades :

void foo() { printf( "foo" ) ; }
void bar() { printf( "bar" } ; }

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

int main( int argc, char** argv )
{
if ( argc > 1 ) FOOBAR() ;
return 0 ;
}

Regarde le comportement avec et sans le do/while (et c'est encore
plus drole si on rajoute un else)



Pourquoi pas simplement:
#define FOOBAR() {foo(); bar();}
?



Bonne question.

A premiere vue, la version do/while necessite l'ajout d'un
point-virgule, pas la version "simple". Je ne sais pas si
c'est suffisant, mais dans la pratique j'ai souvent vu la
premiere, et je crois jamais la deuxieme, mais cet avis
est forcement biaisé : la forme bizarre de la version
do/while fait qu'on la retient mieux que l'autre ;)
Avatar
Charlie Gordon
"Michel Decima" a écrit dans le message de
news: gbdka7$89c$
Pierre Maurette a écrit :

Pourquoi pas simplement:
#define FOOBAR() {foo(); bar();}
?



Bonne question.

A premiere vue, la version do/while necessite l'ajout d'un
point-virgule, pas la version "simple". Je ne sais pas si
c'est suffisant, mais dans la pratique j'ai souvent vu la
premiere, et je crois jamais la deuxieme, mais cet avis
est forcement biaisé : la forme bizarre de la version
do/while fait qu'on la retient mieux que l'autre ;)



Cette forme ne fonctionne pas dans le cas suivant:

if (toto)
FOOBAR();
else
FOOFOO();

en effet on a l'expansion suivante:

if (toto)
{foo(); bar();};
else
FOOFOO();

qui est un erreur de syntaxe parce que ``{xxx};'' cela fait 2 statements
alors que ``do{xxx}while(0);'' n'en fait qu'un.

Moralité: les macros c'est du poison, voici quelques règle de cuisine:

* il faut toujours parentheser les arguments dans l'expansion, et
l'expansion elle-meme si c'est une expression,
* il faut faire en sorte que l'expansion soit une expression ou un statement
unique sans ; final, en utilisant eventuellement l'astuce do/while(0)
* il faut evaluer les arguments une fois et une seule dans l'expansion,
* dans le cas ou la regle ci-dessus est impraticable, il faut que le nom de
la macro soit en majuscules.
* dans les cas ou c'est possible, on preferera utiliser une fonction static
inline

--
Chqrlie
Avatar
Antoine Leca
En news:gbd3gl$f2c$, Patrick Lamaizière va escriure:
Quel est l'intérêt profond de déclarer des macros en do { } while (0)?



Pouvoir mettre un appel de la dite macro comme instruction unique
(c'est-à-dire SANS {}) comme sujet d'une construction if()/while()/for()
etc.

C'est en fait l'équivalent pour les instructions de la paire de parenthèses
englobantes qui est (hautement) recommandée pour les expressions dans les
macros.


Par exemple dans l'idée:

#define PRINT(x) do {
printf(x);
} while (0)



Aucun intérêt réel ici, puisqu'il n'y a pas d'expansion¹.
Mais si tu considères le peu différent
#define PRINT(x) do {
fprintf(journal, x);
printf(x);
} while (0)

cela permet d'écrire ensuite

if( tout_va_bien(toto) )
PRINTX(toto);

sans introduire un bogue très vicieux, qui se manifestera (probablement par
un SSIGSEGV ou similaire) seulement le jour où tout_ne_va_pas_bien...


Antoine
____________
¹: sauf dans le cas puant où en fait printf() est une macro mal définie
comme
#define printf(x) machine(x); truc(x);
Mais bon, je néglige parce que un tel truc est du domaine de la pourriture
impossible à rencontrer dans la réalité.
Avatar
-ed-
On 24 sep, 16:34, Pierre Maurette wrote:
Pourquoi pas simplement:
#define FOOBAR()  {foo(); bar();}



Pfff... Sujet achi épuisé. Tu en es encore là ?

C'est pour forcer l'usage du ';'