2010-08-20 6 views
5

J'essaye d'instrument de code pour attraper et imprimer les messages d'erreur. Actuellement, je suis sur un somethng macro comme ceci:Utilisation et retour de la sortie dans la macro C

#define my_function(x) \ 
    switch(function(x)) { \ 
    case ERROR: \ 
     fprintf(stderr, "Error!\n"); \ 
     break; \ 
    } 

Normalement, je ne capture la sortie de fonction et cela fonctionne très bien. Mais j'ai trouvé quelques cas où j'ai aussi besoin de la valeur de retour de function(). J'ai essayé quelque chose comme le suivant, mais cela produit une erreur de syntaxe.

#define my_function(x) \ 
    do { \ 
    int __err = function(x); \ 
    switch(__err) { \ 
     case ERROR: \ 
     fprintf(stderr, "Error!\n"); \ 
     break; \ 
    } \ 
    __err; \ 
    } while(0) 

je pouvais déclarer une variable globale pour maintenir la valeur de retour de la fonction, mais qui semble laid et mon programme est multithread, donc qui est susceptible de causer des problèmes. J'espère qu'il existe une meilleure solution.

+1

Pourquoi ne pas en faire une fonction en ligne? – Job

+1

La "sortie" d'une fonction n'est pas la même que la "valeur de retour" d'une fonction. Vous voulez la valeur de retour. –

+2

Il manque plusieurs marqueurs de continuation de ligne à votre message. Cela peut être votre erreur de syntaxe. –

Répondre

6

Ceci est un code relativement compliqué, il n'y a pas beaucoup de raisons de l'avoir dans une macro. Faites-le inline (C99) ou static (C89) ou les deux si vous voulez vraiment le placer dans un fichier d'en-tête. Avec tout compilateur raisonnable, cela devrait donner la même efficacité qu'une macro.

+0

Une fonction inline ne peut malheureusement pas faire certaines des astuces d'une macro, comme la concaténation d'identifiants ('FOO ## _size' à partir d'un code généré que j'utilise, par exemple). Sinon, oui, veuillez utiliser les fonctions en ligne. – thirtythreeforty

1

Il manque 2 \ dans votre deuxième expression (ligne 2 et 3), est-ce correct?

+0

Désolé, juste des fautes de frappe –

+0

+1 Aucune raison de baisser cette réponse –

+0

Je viens de downvoted parce que cela ne répond pas à la question puisque l'erreur de syntaxe n'était pas liée aux fautes de frappe. –

25

GCC a une fonction appelée statement expressions

Donc, si définir macro comme

#define FOO(A) ({int retval; retval = do_something(A); retval;}) 

que vous pourrez utiliser comme comme

foo = FOO(bar); 
+1

C'est essentiellement ce que j'essayais de faire avec ce qui précède. Je pense que @Jens avait raison de dire qu'une fonction en ligne convient mieux à mes besoins. –

1

Désolé, c'est modifié ..

  1. Je pense que vous avez juste besoin des accolades. Assurez-vous que les antislashs sont les derniers caractères de chaque ligne (pas d'espace après).
  2. Si vous avez besoin pour obtenir la valeur err de la macro, vous pouvez simplement ajouter un paramètre

comme ceci:

#define my_function(x, out) \ 
     { \ 
     int __err = function(x); \ 
     switch(__err) { \ 
      case ERROR: \ 
      fprintf(stderr, "Error!\n"); \ 
      break; \ 
     } \ 
     __err; \ 
     (*(out)) = _err; \ 
     } 

Pour conserver le passage par référence paradigme C, vous devrait appeler my_function cette façon:

int output_err; 

my_function(num, &output_err); 

de cette façon, plus tard, si vous décidez de faire my_function une fonction réelle, vous n'avez pas besoin de changer les références d'appel. Btw, "Statement Expressions" de qrdl est aussi un bon moyen de le faire.

-1

Il n'est pas nécessaire de déclarer une variable si votre fonction retourne quelque chose, alors vous pouvez directement obtenir cette valeur. Par exemple:

#define FOO(A) do_something(A) 

Ici do_quelquechose renvoie un nombre entier. Ensuite, vous pouvez facilement l'utiliser comme:

int a = FOO(a); 
+1

Cela ne fonctionne pas dans ma situation car la macro doit également utiliser la sortie de 'do_something' et la seule façon d'adopter l'approche que vous proposez est d'appeler' do_something' deux fois. –

3

Une réponse très en retard. Mais néanmoins.Je suis d'accord sur le fait que les fonctions en ligne sont meilleures, mais les MACRO offrent de jolis effets d'impression que vous ne pouvez pas obtenir avec les fonctions en ligne. Je suis d'accord avec @qrdl que vous pouvez utiliser des expressions d'instruction si vous avez restructuré un peu vos instructions. Voici comment cela fonctionnerait avec une macro -

#define my_function(x, y) ({ \ 
    int __err = 0; \ 
    do { \ 
    __err = function(x, y); \ 
    switch(__err) { \ 
     case ERROR: \ 
     fprintf(stderr, "Error!\n"); \ 
     break; \ 
    } \ 
    } while(0); \ 
    __err; \ 
}) 
+0

'({...})' travailler dans n'importe quel compilateur? est une extension GNU C https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html – JuanPablo

+1

n'est pas le faire-alors inutile ici? – Traummaennlein

Questions connexes