web-dev-qa-db-fra.com

Comment trouver le nom de la fonction actuelle lors de l'exécution?

Après des années d'utilisation de la grosse macro MFC ASSERT laide, j'ai finalement décidé de l'abandonner et de créer la macro ASSERT ultime.

Je suis bien pour obtenir le fichier et le numéro de ligne, et même l'expression qui a échoué. Je peux afficher une boîte de message avec ces boutons dans et Abandonner/Réessayer/Annuler.

Et lorsque j'appuie sur Réessayer, le débogueur VS passe à la ligne contenant l'appel ASSERT (par opposition au désassemblage quelque part comme certaines autres fonctions ASSERT). Donc, tout fonctionne à peu près.

Mais ce qui serait vraiment cool serait d'afficher le nom de la fonction qui a échoué .

Ensuite, je peux décider de le déboguer sans essayer de deviner dans quelle fonction il se trouve à partir du nom de fichier.

par exemple. si j'ai la fonction suivante:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   ASSERT(lpCreateStruct->cx > 0);
   ...
}

Ensuite, lorsque ASSERT se déclenche, la boîte de message affiche quelque chose comme:

Function = CMainFrame::OnCreate

Alors, quelle est la façon la plus simple de trouver le nom de la fonction actuelle, lors de l'exécution?

Il ne devrait pas utiliser MFC ou le framework .NET, même si j'utilise les deux.
Il devrait être aussi portable que possible.

36
demoncodemonkey

Votre macro peut contenir le __FUNCTION__ macro. Ne vous y trompez pas, le nom de la fonction sera inséré dans le code développé à au moment de la compilation, mais ce sera le nom de fonction correct pour chaque appel à votre macro. Il semble donc que cela se produit au moment de l'exécution;)

par exemple.

#define THROW_IF(val) if (val) throw "error in " __FUNCTION__

int foo()
{
    int a = 0;
    THROW_IF(a > 0); // will throw "error in foo()"
}
52
Assaf Lavie

La macro du préprocesseur C++ __FUNCTION__ donne le nom de la fonction.

Notez que si vous l'utilisez, ce n'est pas vraiment obtenir le nom de fichier, le numéro de ligne ou le nom de la fonction lors de l'exécution. Les macros sont développées par le préprocesseur et compilées.

Le __FUNCTION__ macro, comme __LINE__, et __FILE__, fait partie de la norme de langue et est portable.

Exemple de programme:

#include <iostream>
#using namespace std;

void function1()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
}
int main()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
        function1();
        return 0;
}

production:

 mon nom de fonction est: principal 
 mon nom de fonction est: fonction1 
23
YenTheFirst

Il n'y a pas de solution standard. Cependant, BOOST_CURRENT_FUNCTION est portable à toutes fins pratiques. L'en-tête ne dépend d'aucun des autres en-têtes Boost, il peut donc être utilisé de manière autonome si la surcharge de la bibliothèque entière est inacceptable.

18
fizzer
10
DaClown

Dans GCC, vous pouvez utiliser la macro __PRETTY_FUNCTION__.
Microsoft a également une macro __func__ Équivalente bien que je ne l'ai pas disponible pour l'essayer.

par exemple. d'utiliser __PRETTY_FUNCTION__ en mettant quelque chose comme ça au début de vos fonctions et vous obtiendrez une trace complète

void foo(char* bar){
  cout << __PRETTY_FUNCTION__ << std::endl
}

qui sortira

void foo(char* bar)

Vous avez également les macros __FILE__ Et __LINE__ Disponibles sous tous les compilateurs c/c ++ standard si vous souhaitez générer encore plus d'informations.

Dans la pratique, j'ai une classe spéciale de débogage que j'utilise à la place de cout. En définissant les variables d'environnement appropriées, je peux obtenir une trace complète du programme. Vous pourriez faire quelque chose de similaire. Ces macros sont incroyablement pratiques et c'est vraiment génial de pouvoir activer le débogage sélectif comme celui-ci sur le terrain.

EDIT: apparemment __func__ Fait partie de la norme? ne le savait pas. Malheureusement, il ne donne que le nom de la fonction et non les paramètres. J'aime le __PRETTY_FUNC__ De gcc mais ce n'est pas portable pour les autres compilateurs.

GCC prend également en charge __FUNCTION__.

8
Matt

Vous pouvez utiliser le __FUNCTION__ macro qui au moment de la compilation sera étendu au nom de la fonction.

Voici un exemple de la façon de l'utiliser dans une macro d'assertion.

#define ASSERT(cond) \
    do { if (!(cond)) \
    MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\
    } while(0)

void MessageBoxFunction(const char* const msg,  ...)
{
    char szAssertMsg[2048];

    // format args
    va_list vargs;
    va_start(vargs, msg);
    vsprintf(szAssertMsg, msg, vargs);
    va_end(vargs);

    ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK);
}
5
Andrew Grant

vous pouvez facilement utiliser func. il reprendra votre nom de fonction actuel lors de l'exécution, ce qui a déclenché l'exception.

usage:

cout << __func__ << ": " << e.what();
0
Hosein Basafa