2010-01-29 7 views
1

gcc 4.4.2 c89Création de macros fonctionnelles

J'ai cet extrait de code que je dois répéter dans une grande partie de mon code. Je me demande simplement s'il existe un moyen de raccourcir l'utilisation d'une fonction macro?

Il y a le code que je voudrais changer.

ERR_INFO error_info; /* create error object */ 
ErrorInfo(&error_info); /* pass the address for it to be filled with error info */ 
fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); /* display the error msg */ 

Et ma tentative de créer une fonction macro pour l'utiliser.

#define DISPLAY_ERR(error_info) ErrorInfo(&error_info) error_info.msg 
fprintf(stderr, "And the error is? [ %s ]\n", DISPLAY_ERR); /* display the error 

Toute suggestion serait plus utile,

+0

Le terme est "macro de type fonction", pas "fonction macro". –

+0

Je suis corrigé. – ant2009

+1

Cette "macro fonctionnelle" particulière serait mieux d'être une fonction réelle. Il semble y avoir très peu ou pas d'avantage à en faire une macro à la place. –

Répondre

6

Si vous voulez vraiment une macro:

#define DISPLAY_ERR(error_info) \ 
    do \ 
    { \ 
     ErrorInfo(&(error_info)); \ 
     fprintf(stderr, "And the error is? [ %s ]\n", (error_info).msg); \ 
    } while(0) 

Vous devez le do... while(0) en raison d'un good reason.

Ensuite, vous appelez votre macro lorsque vous voulez imprimer l'erreur:

if (error) { 
    DISPLAY_ERR(error_info); 
    /* more statements if needed */ 
} 

Je suppose que error_info a été défini quelque part. Dans le cas contraire, ou si vous ne voulez pas, vous pouvez changer votre définition de macro et utilisez:

#define DISPLAY_ERR() \ 
    do \ 
    { \ 
     ERR_INFO error_info; 
     ErrorInfo(&error_info); \ 
     fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); \ 
    } while(0) 

if (error) { 
    DISPLAY_ERR(); 
    /* more statements if needed */ 
} 
+1

Pas de parenthèses supplémentaires autour de 'error_info'? –

+0

@Mike: vous avez raison, je devrais ajouter les parenthèses. Pour ma défense, je ne définirais pas une macro pour cette tâche moi-même :-) –

+0

@Alok. Pourquoi ne pas définir une macro pour cette tâche? Quels critères utilisez-vous pour décider si vous souhaitez créer une macro pour une tâche spécifique? – ant2009

1

Êtes-vous en train de créer une macro qui « renvoie » une valeur? En C++, vous pouvez utiliser l'opérateur de virgule , pour évaluer l'expression de gauche, puis renvoyer l'expression correcte. Vous pouvez faire la même chose en C, aussi.

(foo(var), var.field) // foo(...)is evaluated first, 
         // then second expression is returned 

également

DISPLAY(message) // Pass an argument to macro 
1

Vous devez le faire fonctionner comme un appel de fonction, il peut être utilisé partout un appel de fonction peut, à l'exception sans valeur retournée. Vous devez également marquer les extrémités des lignes intermédiaires avec un antislash. Et l'idiome «do { ... } while (0) est utile dans ce contexte:

#define DISPLAY_ERR() do { ERR_INFO error_info; ErrorInfo(&error_info); \ 
    fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); } while (0) 

La variable error_info est locale au bloc, de sorte que vous ne pas se rappeler de le déclarer dans les fonctions où vous utilisez la macro (ou l'ont comme fichier statique ou, péris la pensée, variable globale).

Notez que ce code ne retourne pas de valeur, mais il peut être utilisé partout dans une fonction qu'une expression void pourrait être utilisé:

if (somefunc() != 0) 
    DISPLAY_ERR(); 
else if (anotherfunc() != 0) 
    DISPLAY_ERR(); 
else 
    do_something_useful_after_all(); 

Etc.

je ne voudrais encore faire Bien sûr, j'ai mesuré les frais généraux d'utilisation d'une fonction régulière plutôt que d'avoir la macro comme une fonction. Utilisé assez souvent, vous pourriez être encore mieux avec une vraie fonction.

1

Il y a deux façons dont vous pouvez le faire. Vous pouvez utiliser l'opérateur de virgule:

#define DISPLAY_ERR(error_info) (ErrorInfo(&(error_info)),(error_info).msg) 

...ou vous pouvez changer la fonction ErrorInfo() de telle sorte que sa valeur retour est le pointeur que vous passez:

#define DISPLAY_ERR(error_info) (ErrorInfo(&(error_info))->msg) 

(et quelques options en plus).