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.
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()"
}
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
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.
__FUNCTION__
ou __FUNC__
ou __PRETTY_FUNCTION__
http://msdn.Microsoft.com/en-us/library/b0084kay (VS.80) .aspxhttp://gcc.gnu.org/onlinedocs/gcc/Function -Names.html
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__
.
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);
}
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();