2010-05-04 7 views
5

Ho una classe molto semplice, denominata Basic, utilizzata in quasi tutti gli altri file in un progetto più grande. In alcuni casi, è necessario eseguire l'output di debug, ma in modalità di rilascio, questo non deve essere abilitato ed essere un NOOP.Prestazioni C++, compilatore ottimizzante, funzione vuota in .cpp

Attualmente è presente una definizione nell'intestazione, che attiva o disattiva un pulsante, a seconda dell'impostazione. Quindi questo è sicuramente un NOOP, quando spento. Mi chiedo, se ho il seguente codice, se un compilatore (MSVS/gcc) è in grado di ottimizzare la chiamata di funzione, in modo che sia di nuovo un NOOP. (Facendo ciò, lo switch potrebbe essere in .cpp e lo switching sarà molto più veloce, compilare/link time saver).

--Header-- 
void printDebug(const Basic* p); 

class Basic { 
    Basic() { 
     simpleSetupCode; 

     // this should be a NOOP in release, 
     // but constructor could be inlined 
     printDebug(this); 
    } 
}; 
--Source-- 
// PRINT_DEBUG defined somewhere else or here 
#if PRINT_DEBUG 
void printDebug(const Basic* p) { 
    // Lengthy debug print 
} 
#else 
void printDebug(const Basic* p) {} 
#endif 

risposta

2

Come per tutte le domande di questo tipo, la risposta è - se è veramente importante per voi, provate l'approccio e esaminare il linguaggio assembly emessa.

+11

Devil's advocate: non copre un'alta percentuale di domande su questo sito? Perché le persone vengono qui? Perché loro non lo sanno. E perché o non sanno come scoprirlo (in questo caso forse non parlano assemblea), o sono troppo pigri o frettolosi per farlo. Meta-domanda: vogliamo escludere le persone pigre/frettolose e rispondere solo a chi non lo sa veramente? Alcuni potrebbero essere scocciati dalle FAQ (e possono saltarli); alcuni potrebbero assaporare le pinte di nuovo e di nuovo per fondamentalmente la stessa domanda. L'OP dovrebbe aver cercato almeno questo sito (o google), anche se – Mawg

+0

@mawg. Copre molti degli usi di questo sito, ed è mia opinione che probabilmente il 50% delle domande pubblicate qui non dovrebbe essere richiesto. Questo in particolare viene ripetutamente richiesto e la mia risposta è quella onesta: non possiamo dire cosa farà il vostro ottimizzatore con il vostro codice, solo voi potete farlo. –

+6

(-1) Quindi la tua risposta non è veramente "utile" per l'utente. In realtà non hai risposto alle loro domande, indipendentemente dal fatto che fosse una domanda appropriata o meno. In realtà, non hai votato per chiudere come duplicato. Se chiedo "cosa è 2 + 2" e dici "capisci da solo" non sei * utile * e non sei * corretto *. È vero che dovrei capirlo da solo, ma non mi hai risposto *. La tua risposta dovrebbe essere un commento. – DevinB

1

Il compilatore può eventualmente ottimizzare questo codice, se conosce l'implementazione della funzione printDebug al momento della compilazione. Se printDebug si trova in un altro modulo di oggetto, questo probabilmente può essere ottimizzato solo dal linker, utilizzando l'intera ottimizzazione del programma. Ma l'unico modo per testare questo è leggere il codice assembly generato dal compilatore. Se si dispone già di PRINT_DEBUG macro, è possibile estenderla dal modo come TRACE è definito:

 
#define PRINT_DEBUG // optional 
#ifdef PRINT_DEBUG 
#define PRINT_DEBUG_CALL(p) printDebug(p) 
#else 
#define PRINT_DEBUG_CALL(p) 
#endif 


void printDebug(const Basic* p); 

class Basic { 
    Basic() { 
     simpleSetupCode; 

     // this should be a NOOP in release, 
     // but constructor could be inlined 
     PRINT_DEBUG_CALL(this); 
    } 
}; 
--Source-- 
// PRINT_DEBUG defined somewhere else or here 
#if PRINT_DEBUG 
void printDebug(const Basic* p) { 
    // Lengthy debug print 
} 
#endif 
+0

è esattamente ciò che viene utilizzato. Ma passando avanti e indietro usando quella definizione, un progetto ricompila. – Dodo

+0

In realtà, questo non è quello che viene utilizzato, in base al codice. Nella mia versione, la funzione printDebug e le chiamate ad esso non esistono nel programma, quando PRINT_DEBUG non è definito. Sulla ricompilazione, sì, entrambe le versioni richiedono la ricompilazione. Ma non puoi aspettarti che il compilatore ottimizzi le chiamate alle funzioni vuote senza ricompilare ... –

+0

Mi dispiace che non sia stato chiaro. Il codice che ho scritto nella domanda, non è il codice in uso dalla classe Basic all'interno del mio progetto. Tuttavia, il codice che hai fornito è fondamentalmente il codice uguale come lo stato corrente della classe Basic all'interno del mio progetto. Con il codice fornito nella domanda, il tempo di compilazione e collegamento è notevolmente ridotto, rispetto alla versione fornita da altri, quando si definisce/non definisce il flag PRINT_DEBUG. – Dodo

0

ERRm, perché non utilizzare il pre-processore di macro in modo diverso?

Proprio della parte superiore della mia testa, qualcosa di simile a:

#define DEBUG_TRACE(p) 
    #ifdef PRINT_DEBUG 
    printDebug(p); 
    #else 
    ; 
    #endif 
+0

Questo non è diverso da quello che viene utilizzato, solo scritto in modo diverso. – Dodo

0

Attualmente la maggior parte delle ottimizzazioni sono fatte al momento della compilazione. Alcuni compilatori come LLVM sono in grado di ottimizzare al momento del collegamento. Questa è un'idea davvero interessante. Ti suggerisco di dare un'occhiata.

In attesa di questo tipo di ottimizzazione, quello che puoi fare è il seguente. Definisci una macro che ti permetta di includere la seguente dichiarazione a seconda che DEBUG sia definito o meno.

#ifdef DEBUG 
#define IF_DEBUG (false) {} else 
#else 
#define IF_DEBUG 
#endif 

È possibile l'utilizzo come questo

Basic() { 
     simpleSetupCode; 

     // this should be a NOOP in release, 
     // but constructor could be inlined 
     IF_DEBUG printDebug(this); 
    } 

che è già molto più leggibile di

Basic() { 
     simpleSetupCode; 

     // this should be a NOOP in release, 
     // but constructor could be inlined 
#if DEBUG 
     printDebug(this); 
#endif 
    } 

noti che è possibile utilizzarlo come se fosse una parola chiave

IF_DEBUG { 
    printDebug(this); 
    printDebug(thas); 
} 
1
#if PRINT_DEBUG 
#define printDebug _real_print_debug 
#else 
#define printDebug(...) 
#endif 

In questo modo il preprocessore eliminerà tutto il codice di debug prima che arrivi anche al compilatore.