2009-02-27 13 views
114

Presumendo che il compilatore C++ li supporta, c'è qualche motivo particolare non utilizzare __FILE__, __LINE__ e __FUNCTION__ a fini di registrazione e il debug?__FILE__, __LINE__, e l'uso di __FUNCTION__ in C++

Sono principalmente interessato a fornire all'utente dati fuorvianti, ad esempio, riportando il numero di riga o la funzione errati come risultato dell'ottimizzazione o come risultato di un impatto sulle prestazioni.

In sostanza, posso fidarmi __FILE__, __LINE__ e __FUNCTION__-sempre fare la cosa giusta?

+0

__LINE__ dovrebbe fare la cosa giusta. L'ho usato e le sue coorti in modo esteso, tra cui __PRETTY_FUNCTION__. ... Ma ... beh, sto proprio ora guardando il codice in cui __LINE__ mente. Probabilmente perché si trova in un blocco catch per la gestione delle eccezioni try/catch. –

+2

rilevante: [riferimento gcc per macro predefinite] (http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html) –

risposta

140

__FUNCTION__ non standard, __func__ esiste in C99/C++ 11. Gli altri (__LINE__ e __FILE__) stanno bene.

Riporterà sempre il file e la linea corretti (e la funzione se si sceglie di utilizzare __FUNCTION__/__func__). L'ottimizzazione è un non fattore poiché è un'espansione macro del tempo di compilazione; sarà mai effetto effetto in alcun modo.

+2

'__func__' è una specie di problema in C++. C99 non dice una parola sugli argomenti predefiniti e così via, casi in cui non è così ovvio come '__func__' dovrebbe comportarsi in C++. – wilhelmtell

+3

@thr: mentre fai un buon punto. Ero abbastanza chiaro che '__func__' esiste in c99, non C++. Indipendentemente da ciò, penso che un'implementazione ragionevole di '__func__' in C++ provocherebbe solo il nome storpiato. Dal momento che non sono uno scrittore di compilatori, non è proprio la mia chiamata. –

+0

Quali compilatori non supportano '__FUNCTION__'? Quali compilatori tranne il recente gcc trattano questo come una variabile, non una macro? – basin

7

Personalmente, sono riluttante a utilizzarli per qualsiasi cosa tranne il debug dei messaggi. L'ho fatto, ma cerco di non mostrare questo tipo di informazioni ai clienti o agli utenti finali. I miei clienti non sono ingegneri e talvolta non sono esperti di computer. Potrei registrare queste informazioni sulla console, ma, come ho detto, a malincuore tranne che per le build di debug o per gli strumenti interni. Suppongo che dipenda dalla base di clienti che hai, però.

+21

"Potrei loggare queste informazioni alla console" - o meglio ancora: registrarlo in un file in modo che se qualcosa va storto puoi chiedere al cliente di inviarlo ... – Christoph

30

In rari casi può essere utile modificare la linea fornita da __LINE__ a qualcos'altro. Ho visto GNU configure che per alcuni test riportava numeri di linea appropriati dopo aver inserito del voodoo tra le righe che non compaiono nei file di origine originali. Per esempio:

#line 100 

farà le seguenti righe cominciano con __LINE__ 100. È possibile opzionalmente aggiungere un nuovo file-name

#line 100 "file.c" 

E 'solo raramente utile. Ma se è necessario, non ci sono alternative che io conosca. In realtà, al posto della linea, può essere utilizzata anche una macro che deve risultare in una qualsiasi delle due forme precedenti. Utilizzando la libreria Boost preprocessore, è possibile incrementare la riga corrente del 50:

#line BOOST_PP_ADD(__LINE__, 50) 

ho pensato che sia utile ricordare che, dal momento che hai chiesto di utilizzo di __LINE__ e __FILE__. Uno non ottiene abbastanza sorprese su C++ :)

Edit: @ Jonathan Leffler fornisce alcuni più buoni casi d'uso nei commenti:

scherzi con #line è molto utile per i pre-processori che desidera mantenere gli errori segnalati nel codice C dell'utente in linea con il file sorgente dell'utente. Lo fanno Yacc, Lex e (più a casa mia) i preprocessori ESQL/C.

22

FYI: g ++ offre la macro __PRETTY_FUNCTION__ non standard. Fino a poco tempo fa non sapevo di C99 __func__ (grazie Evan!).Penso di preferire ancora __PRETTY_FUNCTION__ quando è disponibile per l'ambito della classe extra.

PS:

static string getScopedClassMethod(string thePrettyFunction) 
{ 
    size_t index = thePrettyFunction . find("("); 
    if (index == string::npos) 
    return thePrettyFunction; /* Degenerate case */ 

    thePrettyFunction . erase(index); 

    index = thePrettyFunction . rfind(" "); 
    if (index == string::npos) 
    return thePrettyFunction; /* Degenerate case */ 

    thePrettyFunction . erase(0, index + 1); 

    return thePrettyFunction; /* The scoped class name. */ 
} 
+0

Bello sapere di \ _ \ _ PRETTY_FUNCTION \ _ \ _. Molto utile! – Maverobot

4

li uso per tutto il tempo. L'unica cosa di cui mi preoccupo è dare via IP nei file di log. Se i nomi delle tue funzioni sono davvero validi, potresti rendere più facile scoprire un segreto commerciale. È una specie di spedizione con i simboli di debug, solo più difficile da trovare le cose. Nel 99,999% dei casi non ne uscirà niente di male.

+0

Buon punto di vista. È banale estrarre queste informazioni usando l'utility 'strings' per estrarre tutti i dati simili a stringhe dall'eseguibile. È possibile estrarre anche eseguibili compressi. Sii molto attento a ciò che invii a un sito cliente. Spesso i concorrenti sono in grado di mettere le mani sui tuoi eseguibili, anche se non dovrebbero farlo. – Marty

Problemi correlati