[gull] cours C++

Leopoldo Ghielmetti leopoldo.ghielmetti at a3.epfl.ch
Thu Mar 2 13:49:57 CET 2006


On Thu, 2006-03-02 at 12:08 +0100, Marc SCHAEFER wrote:
> On Thu, Mar 02, 2006 at 10:58:54AM +0100, Leopoldo Ghielmetti wrote:
> > Dans le cas de la macro de debug MA_MACRO il faut la définir comme ça:
> > #ifdef DEBUG
> > #  define MA_MACRO(x) do{function(x); debug(x);}while(0)
> > #else /* !DEBUG */
> > #  define MA_MACRO(x) function(x)
> > #endif /* DEBUG */
> 
> { function(x); debug(x) }  suffit probablement pour créer un bloc.

Oui, mais il y a des problèmes car un bloc ne se comporte pas exactement
comme une instruction tandis que do {} while(0) est vu par le
compilateur de la meme manière qu'une commande.

p.e.:
if (arg)
  MA_MACRO;
else
  printf("salut\n");

passe avec ma macro mais donne erreur avec un bloc, or pour bien
respecter la syntaxe du C et du C++ après chaque commande il faut un
point-virgule, ce qui est parfaitement respecté par ma macro.

Si par contre on construit un bloc le precompilateur va substituer de
ces deux façons:
if (arg)
  do{function(x); debug(x);}while(0);
else
  printf("salut\n");

et

if (arg)
  function(x);
else
  printf("salut\n");

avec un bloc on serait obligé d'écrire:
if (arg)
  MA_MACRO
else
  printf("salut\n");

ce qui conduit à:
if (arg)
  {function(x); debug(x);}
else
  printf("salut\n");

et

if (arg)
  function(x)  // erreur, il manque le ;
else
  printf("salut\n");

Pour corriger ceci il faut donc définir la macro en incluant le
point-virgule:
#  define MA_MACRO function(x);

mais qui va poser d'autres problèmes. Moi personnellement je préfère ne
jamais mettre les points-virgule dans les macro. Surtout si après on
désire utiliser la commande indent ou la capacité d'indentation
automatique de emacs ou autre éditeur.

En plus ça risque de poser d'autres problèmes dans le cas ou on
déciderait de modifier la macro après coup. On risque de voir apparaître
des erreurs dans le code.

Je préfère classer les macros en deux categories principales, les
procedures et les fonctions.
Les procedures sont celles qui se comportent comme n'importe quelle
fonction C qui ne retourne pas de valeur et je les entoure par
do{...}while(0) et les fonctions qui retournent des valeurs et qui sont
simplement entourées par (...).

Donc la classique MAX est une fonction car elle retourne une valeur et
elle est simplement entourée de ():
#define MAX(a,b) ((a)>(b)?(a):(b))

La macro précédente MA_MACRO est une procédure car elle ne retourne pas
de valeur, donc je l'entoure de do{}while(0).

Les macros de type fonction peuvent être dangereuses car il faut faire
attention a quels valeurs on leur donne car on ne peut pas éviter les
pièges style MAX(a++,b). Les macros de type procédure peuvent être
protèges, par exemple:
#include <iostream>

#define printMAX(a,b) do{int a1=(a), b1=(b); std::cout << (a1>b1?a1:b1)
<< "\n";}while(0)

int main(void)
{
  int i=0;
  while(i<10)
    {
      std::cout << i << " ";
      printMAX(i++,5);
    }

  return 0;
}

donne bien le résultat qu'on s'attend si on sait pas qu'il s'agit d'une
macro:
0 5
1 5
2 5
3 5
4 5
5 5
6 6
7 7
8 8
9 9

malgré le i++ dans l'appel de la macro.

> >Et si on sait p.e. que la variable x est un entier (chose qui est
> > définie par le type des fonctions) il pourra aussi protéger x d'une
> > mauvaise utilisation de la façon suivante:
> > #  define MA_MACRO(x) do{int xx=(x); function(xx); debug(xx);}while(0)
> 
> juste, mais dans ce cas, une fonction inline (bon, spécifique gcc, à ma
> connaissance) est meilleure, comme tu le montres plus bas.
> 
> > Clairement ce genre de macro ont tout leur sens dans la programmation C.
> > En C++ il y a des solutions plus élégantes mais savoir écrire une bonne
> > macro est fondamental pour la programmation en C et dérivés.
> 
> Exact ;)
> 
> maintenant, combien de programmeurs C ici présents (s'il en reste :))
> ont compris le problème que je soulevais ?

Je ne sais pas, il y a toujours trop de monde qu'ignore la plupart des
problèmes liés au C, en primis les pointeurs qui le plus souvent sont
mal exploités.

> Mon but était d'attirer l'attention des dangers de tout ce qui touche au
> préprocesseur.

Oui, je comprends, mais les dangers sont présents dans tous les langages
de programmation (et humains aussi) et il faut apprendre à les
maîtriser. Rendre attentif quelqu'un est louable et c'est ce que je suis
en train de faire aussi en écrivant sur cette liste. :-)

ciao, Leo





More information about the gull mailing list