2009-03-24 13 views
33

Dopo anni di utilizzo della grossa macro MFC ASSERT, ho finalmente deciso di abbandonarlo e creare la macro ASSERT definitiva.Come trovare il nome della funzione corrente in fase di esecuzione?

Sto soddisfacendo il numero di file e di riga e persino l'espressione non riuscita. Posso visualizzare una messagebox con questi pulsanti in, e Abort/Retry/Cancel.

E quando si preme Riprova, il debugger VS salta alla riga contenente la chiamata ASSERT (diversamente dal disassemblaggio da qualche parte come alcune altre funzioni ASSERT). Quindi funziona praticamente tutto.

Ma quello che sarebbe davvero bello sarebbe visualizzare il nome della funzione che ha avuto esito negativo.

Quindi posso decidere se eseguire il debug senza cercare di indovinare quale funzione è presente nel nome file.

ad es. se ho la seguente funzione:

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

Poi, quando i fuochi affermare, il messagebox avrebbe mostrato qualcosa di simile:

Function = CMainFrame::OnCreate 

Allora, qual è il modo più semplice di scoprire il nome della funzione corrente, tempo di esecuzione?

Non deve utilizzare MFC o .NET framework, anche se io li uso entrambi.
Dovrebbe essere il più portabile possibile.

+0

Se si ha accesso a John Robbins [Applicazioni di debug per Microsoft® .NET e Microsoft Windows®] (http://www.amazon.com/Debugging-Applications-Microsoft®-Microsoft-Pro-Developer/dp/0735615365/ref = sr_1_16/175-5814253-7853112? Ie = UTF8 & s = electronics & qid = 1237928779 & sr = 8-16) si dovrebbe assolutamente dare un'occhiata alle asserzioni dalla libreria BugSlayerUtil sul CD in dotazione. Sono specifici per Windows, ma davvero definitivi. – Paul

+0

Ho dato un'occhiata a http://www.koders.com/cpp/fid3653A5E08C30DB8B7551729FBED0BC3D51B19AD8.aspx ma non sembra che mostri il nome della funzione. Perciò penso che la mia versione sia più definitiva della sua: D – demoncodemonkey

+0

Mostra stacktrace. Stacktrace contiene nomi di funzioni, non è vero? – Paul

risposta

48

La macro può contenere la macro __FUNCTION__. Non commettere errori, il nome della funzione sarà inserito nel codice espanso al tempo di compilazione, ma sarà il nome della funzione corretta per ogni chiamata alla macro. Quindi "sembra" accade in fase di esecuzione;)

ad es.

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

int foo() 
{ 
    int a = 0; 
    THROW_IF(a > 0); // will throw "error in foo()" 
} 
+4

Sfortunatamente, '__FUNCTION__' non è standard. '__func__' * è * standard, ma non è una stringa letterale; agisce come una variabile, quindi non è possibile concatenarlo facilmente. – ephemient

+0

a destra. ma fortunatamente l'OP sta usando MFC e quindi la multipiattaforma non è probabilmente un problema. –

+2

L'ho menzionato perché OP chiedeva la portabilità. – ephemient

18

Il preprocessore C++ macro __FUNCTION__ dà il nome della funzione.

Si noti che se si utilizza questo, non è davvero ottenere il nome file, il numero di riga o il nome della funzione in fase di esecuzione. Le macro sono espansi dal preprocessore, e compilati in.

Il __FUNCTION__ macro, come __LINE__, e __FILE__, fa parte del linguaggio standard, ed è portatile.

programma Esempio:

#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; 
} 

uscita:

 
my function name is: main 
my function name is: function1 
+0

__FUNCTION__ non fa parte dello standard di linguaggio C++ (non ho fatto downvoting per questo, ma suppongo che qualcun altro l'abbia fatto) –

+0

buon punto, penso di aver letto qualcosa di sbagliato. secondo http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html, __func__ fa parte dello standard C99 (anche se non necessariamente tutto lo supporta). __FUNCTION__ non lo è, anche se i grandi compilatori (MSDN/GCC) lo supportano, è effettivamente portatile. – YenTheFirst

+1

Nota che __func__ non fa parte di C++. –

4

È possibile utilizzare la __FUNCTION__ macro, che al momento della compilazione sarà espanso nel nome della funzione.

Ecco un esempio di come utilizzarlo in una macro assert.

#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); 
} 
+0

Argh al "..." ma per il resto buona risposta, grazie. – demoncodemonkey

+0

perché devi odiare il '...'? È un codice valido –

+0

@demoncodemonkey: Trevor fa una domanda molto. Perché Andrew non dovrebbe usare una funzione variadica qui? – unforgettableid

18

Non esiste una soluzione standard. Tuttavia, BOOST_CURRENT_FUNCTION è portatile per tutti gli scopi pratici. L'intestazione non dipende da alcuno degli altri header Boost, quindi può essere usato standalone se il sovraccarico dell'intera libreria non è accettabile.

+1

Grazie, non uso Boost (ancora) ma almeno so che c'è un sostituto per __FUNCTION__ se ho mai avuto bisogno di portarlo. – demoncodemonkey

+0

L'intestazione per {{BOOST_CURRENT_FUNCTION}} è indipendente. Puoi semplicemente scaricarlo e inserirlo nella tua base di codice senza altro da Boost. –

7

In GCC è possibile utilizzare la macro __PRETTY_FUNCTION__.
Microsoft ha anche una macro equivalente __func__ anche se non ho quello disponibile per provare.

ad es. utilizzare __PRETTY_FUNCTION__ mettere qualcosa di simile al principio delle vostre funzioni e si otterrà una traccia completa

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

che sarà uscita

void foo(char* bar) 

Hai anche la __FILE__ e __LINE__ macro disponibili in tutti gli standard compilatori c/C++ se vuoi produrre ancora più informazioni.

In pratica ho una speciale classe di debug che uso al posto di cout. Definendo le variabili d'ambiente appropriate posso ottenere una traccia completa del programma. Potresti fare qualcosa di simile. Queste macro sono incredibilmente maneggevoli ed è davvero fantastico poter attivare il debug selettivo come questo sul campo.

EDIT: apparentemente __func__ è parte dello standard? non lo sapevo. Sfortunatamente, fornisce solo il nome della funzione e non i parametri. Mi piace gcc's __PRETTY_FUNC__ ma non è portabile ad altri compilatori.

GCC supporta anche __FUNCTION__.

Problemi correlati