10
votes

Obtenir la dernière fonction appelée C / C ++

J'utilise une API et je me trouve écrire beaucoup de code de traitement des erreurs de la forme générale: xxx

où le corps de impressionError pourrait ressemblent à: xxx

Cependant, il s'agit d'une douleur au code de la fonction à chaque fois. Y a-t-il un moyen d'obtenir le nom de la fonction provoquant l'erreur, c'est-à-dire la dernière fonction appelée , au moment de l'exécution ou à travers une macro? Je ne peux en aucun cas modifier la fonction API, bien sûr. Il existe des moyens d'obtenir le fonction actuelle ainsi que le Fonction d'appel , mais aucun de ces travaux de l'extérieur de la fonction.


5 commentaires

#define error_location __func__, __line__, __fle __ et printError (ErrorCode, error_location); est le long des lignes de ce que je fais habituellement ou mettez l'appel entier dans une macro. Le premier est un peu plus flexible pour avoir une macro pour toutes les surcharges de printError .


@chris je ferais attention avec ça. La meilleure option est de créer une macro paramètre que vous invoquez comme une fonction. Passer trois arguments qui ressemblent à un mène à certaines ... situations intéressantes.


@ RICHARDJ.ROSSIII, Tant qu'il est clair qu'il ne devrait être utilisé que pour appeler des fonctions d'erreur nécessitant la source de l'erreur, je ne vois aucun problème avec celui-ci étant utilisé pour cela. Y a-t-il quelque chose de spécifique que vous aviez à l'esprit?


@chris __ func __ donne la fonction i "m actuellement dans, mais je veux le nom de la fonction API que je viens de rester.


@ 1 '', je vois, j'inclus habituellement cela avec un message personnalisé si je le mettais. Il n'est pas difficile d'adapter quelle que soit la macro que vous utilisez, mais je n'ai pas trouvé de meilleur moyen que les macros à cette fin. C'est l'un des rares fois que j'utiliserai un.


4 Réponses :


5
votes

La solution ici est de faire une macro qui invoque votre fonction, et s'il échoue, appelez une fonction d'impression avec vos paramètres spéciaux. Si vous utilisez C99, vous pouvez (AB) utiliser une macro variable, comme ceci: xxx pré>

Notez que ce qui précède utilise un GCC Extension (qui est également pris en charge dans Clang) qui permet d'adopter des arguments variadiques d'être correctement passés si aucun n'était fourni. p>

qui pourrait ensuite être utilisé comme tel: p> xxx pré>

qui génère ce texte charmant pour votre plaisir de débogage: p>

Error in function fail on line 703 of file /Users/rross/Documents/TestProj/TestProj/main.mm: Couldn't validate results: Context-Sensitive Debug Info


10 commentaires

Notez que c ++ 11 a des macros variadiques aussi :)


@chris en effet, mais en C ++, vous pourriez probablement faire quelque chose de bien meilleur avec les modèles.


Peut-être en dessous, mais pas pour passer le fichier et la ligne :(


@chris de quoi parlez-vous? Vous pouvez passer un const char * dans un modèle tout simplement bien.


Désolé, je voulais dire inclure __ ligne __ et __ fichier __ sans les spécifier explicite explicitement. Seule la substitution de texte des macros peut le faire. Vous pouvez en faire un seul pour le faire et remettre tout l'autre travail à un modèle, cependant.


+1, bien que l'erreur OUPUTS Succès pour le nom de la fonction lorsque vous aviez invoqué échec () .


Élégant, mais quel est le bénéfice de la liste des arguments variable sur quelque chose de plus simple comme la solution de XLC?


@ 1 "Si vous devez mettre plus d'informations de débogage, telles que lors de l'utilisation de Bind , vous pouvez émettre des numéros de socket, des descripteurs de fichier, etc. Avant de planter. Il est toujours bon d'avoir beaucoup d'endroits pour déboguer .


Il vous permet de créer un plus compliqué comme chaîne de format et arguments associés.


C'est assez cool, en fait! Je vais accepter XLC cependant, parce que c'est celui que j'ai réellement utilisé.



9
votes

Vous pouvez avoir ce xxx


7 commentaires

Que fait le #func faire? Contrairement à #Line , ce n'est pas une directive pré-traitement autonome.


@ 1 "Il convertit une argument macro en une chaîne.


+1 avait la même pensée, mais il y a des inconvénients. Le plus grand est que le succès ou l'échec de la callee est caché de l'appelant. Si chaque erreur provoque le programme EXIT , c'est bon, mais si la manipulation est plus nuancée, cela devient un obstacle important.


@jerry Vous pouvez modifier cela pour le faire "renvoyer" le code d'erreur et le vérifier pour la fonction que vous souhaitez des soins supplémentaires. quelque chose comme #define sûre_call (FUNC) ({if (ERRORCODE = (FUNC)), impressionnez (...); ErrorCode;})


Cela ne "retournera" rien, cela ne devrait pas compiler quel que soit la façon dont vous l'utilisez [bien que j'ai été surpris avant :)].


@jerry ({}) est une extension GCC gcc.gnu.org/onlinedocs/gcc/statement-expr.tml#statement-ex PRS


Eh bien, comme je l'ai dit, j'ai été surpris avant :) Encore, cela peut être fait de manière plus portable avec l'opérateur ternaire (aka conditionnel) ou un appel de la fonction (voir ma réponse par exemple, bien que c'est assez simple) .



2
votes

nb: cette solution ne fonctionne que si l'API peut être modifiée ou enveloppée pour modifier le type de retour du code d'erreur. em>

Je renforcerais le code de code code> Valeur avec le nom de la fonction qui renvoie le code. Ensuite, la fonction impressive () code> peut extraire les informations du code code> code> lui-même. P> xxx pré>

donc, la fonction quand Le retour d'une erreur utiliserait: retour error_code (xyz); code>. Le récepteur du code d'erreur reçoit le nom de la fonction de la fonction qui a renvoyé l'erreur. La fonction la plus interne qui a déclenché l'erreur peut même être de retour correctement propagée si le code d'erreur est copié au lieu de réformé. P>

Par exemple: p>

void foo () {
    error_code_type errorCode;
    if ((errorCode = the_api_function()).code) {
        printError(errorCode.code, errorCode.function, __LINE__, __FILE__);
    }
}


6 commentaires

Comme moi, j'ai malheureusement malheureusement malheureusement. Il cherche le nom de la fonction qu'il appelle, pas le nom de celui qu'il est actuellement.


@ RICHARDJ.ROSSIII: Non, j'ai attrapé ça. Lisez ma réponse avec soin.


Ce qui vous manque, c'est que __ func __ est inutile pour ce qu'il tente de faire ici.


@ Richardj.rossiii: le __ func __ est utilisé par la fonction appelée qui a provoqué l'erreur. Il est retourné à l'appelant, l'appelant sait donc quelle fonction a provoqué l'erreur.


Mais je ne peux pas modifier la fonction qui a provoqué l'erreur, car cela fait partie de l'API.


@ 1 '': J'envelopperais moi-même les API afin que je puisse avoir un contrôle complet sur la manière dont l'API est utilisée. Si ce n'est pas une option, je recommanderais la solution de XLC ou de Richardj.rossiii.



1
votes

Solution mise à jour

Si vous n'avez pas Errorcode code> défini (ou ne voulez pas toujours le définir), utilisez ceci à la place: P>

error: call func(1,1,1) shouldn't have returned 1 but did (from function main at line 38 of file prog.c)
error: call func(a,b,c) returned 0 instead of 1 (from function main at line 40 of file prog.c)
error: call func(a,b,1) returned 1 (from function main at line 42 of file prog.c)
error: call func2() returned -1 (from function main at line 44 of file prog.c)
func2 failed error check
error: call funcPoint() returned -1 (from function main at line 53 of file prog.c)
funcPoint failed error check
func passed error check
error: call func3() returned 3 (from function main at line 71 of file prog.c)
retry...
error: call func3() returned 2 (from function main at line 71 of file prog.c)
retry...
error: call func3() returned 1 (from function main at line 71 of file prog.c)
retry...
error: call func(1,2,4) returned 7 (from function main at line 76 of file prog.c)
fatal error 7


1 commentaires

J'ai manqué l'opérateur des virgules là-bas, apparemment.