2012-07-01 21 views
18

Come impedire a GCC di eliminare il codice all'interno di se il blocco (0)?Disabilitare l'eliminazione "if (0)" in gcc

Quando uso Visual Studio, una delle mie tecniche di debug è quello di mettere il codice come questo nel mio programma:

if (0) 
    do_some_debug_printing_and_checking(); 

Poi, quando un punto di interruzione viene colpito, clicco al do_some_debug_printing_and_checking() linea , seleziona "imposta la prossima istruzione" e forza l'esecuzione.

Quando utilizzo gcc/gdb come back-end, l'istruzione "next next statement" non funziona più, poiché GCC rimuove semplicemente il codice dall'interno della dichiarazione if (0).

Sono ovviamente utilizzando il flag -O0 per disabilitare l'ottimizzazione. Ho anche provato il flag -fno-dce -fno-tree-dce per disabilitare esplicitamente l'eliminazione del codice guasto, ma non ha alcun effetto: il contenuto di se (0) non è presente nel file binario e io non è possibile utilizzare impostare la prossima istruzione per saltare dentro.

C'è qualche buon modo per dire a gcc di disabilitare l'eliminazione di se (0) contenuti?

Edit:

Grazie per la soluzione alternativa "variabile aggiuntiva", tuttavia ci sono 2 cose che non mi piacciono a questo proposito:

  1. E 'ancora una riga aggiuntiva di codice
  2. Ha vinto essere ottimizzato automaticamente quando costruisco la versione di rilascio e voglio che quelle cose di debug scompaiano. Sicuramente posso usare # ifdef-s, ma sono anche più linee extra.

Davvero, non c'è assolutamente alcuna possibilità di fare in modo che GCC mantenga quel codice morto?

+1

So che questo non è quello che stavi chiedendo, ma prova utilizzando una variabile globale impostata su false per i tuoi if. In questo modo il compilatore non ottimizzerà le tue istruzioni if. –

+12

Perché non chiamate semplicemente do_some_debug_printing_and_checking() 'in gdb quando volete eseguire quella funzione? – Mat

risposta

12

La cosa più semplice da fare è fare in modo che il controllo dipenda (diciamo) da una variabile con collegamento esterno.

E.g.

extern bool debug; 
if (debug) 
    do_some_debug_printing_and_checking(); 

Il posto in ambito namespace:

bool debug = false; 
+5

Lascerei un 'volatile 'lì. – Kos

+0

@Kos: Perché dovresti farlo? –

+0

in modo che il compilatore non presupponga che il valore della variabile non cambierà tra alcuni due punti – Kos

8

non vorrei contare su bandiere compilatore gcc per fare questo. I flag del compilatore possono cambiare tra le versioni di gcc e cambiano tra i compilatori. Potresti trovarti a dover eseguire il debugging dello stesso codice in sei mesi in Visual C++ ...

@CharlesBailey offre un buon suggerimento su come eseguire questa operazione con una variabile extern. Ecco un'alternativa che non richiede che una variabile sia esposta all'intero modulo o conservata nella memoria statica.

dichiarare una variabile temporanea volatile nel campo di applicazione della dichiarazione if:

if (volatile bool dbg = false) 
{ 
    do_some_debug_printing_and_checking(); 
} 

In questo modo il campo di applicazione della variabile temporanea abbastanza stretta. Il qualificatore volatile non consente al compilatore di assumere nulla sulla variabile o di ottimizzare il ramo.

Una cosa da tenere a mente è che la variabile viene sempre allocata nello stack e verrà tenuta in pila fino all'uscita dalla funzione. Sia questo approccio che l'approccio extern dovrebbero funzionare, ma hanno compromessi leggermente diversi (e probabilmente trascurabili).

Se siete disposti a utilizzare le macro per aiutare a risolvere questo problema, allora si può facilmente disabilitare la variabile temporanea quando il rilascio il codice in produzione:

#ifndef IS_DEBUGGING 
# define IS_DEBUGGING 0 
#endif 

#if IS_DEBUGGING 
# define TMP_DBG_FLAG volatile bool dbg_flag = false 
#else 
# define TMP_DBG_FLAG false 
#endif 

quindi dichiarare la sua dichiarazione if come:

if (TMP_DBG_FLAG) 
{ 
    do_some_debug_printing_and_checking(); 
} 

Quando si definisce IS_DEBUGGING come 1, la variabile locale viene creata, dichiarata volatile e mantenuta. Quando si definisce IS_DEBUGGING come 0, la macro si espande alla costante false e il compilatore ottimizza il ramo. Qualcosa di molto simile potrebbe essere fatto anche per l'approccio extern.

Queste poche righe di codice aggiuntive, ma sono indipendenti dal numero di volte in cui si utilizza TMP_DBG_FLAG. Il codice è anche molto più leggibile rispetto all'utilizzo di tonnellate di ifdef s. La macro potrebbe essere fatto un po 'più sicuro (aggiungendo il valore di __LINE__ ad esso), ma ciò richiederebbe tre macro, e probabilmente non è necessaria:

#if IS_DEBUGGING 
// paste symbols 'x' and 'y' together 
# define TMP_DBG_FLAG_SYMCAT0(x,y) x ## y 

// need one level of indirection to expand __LINE__... 
# define TMP_DBG_FLAG_SYMCAT(x,y) TMP_DBG_FLAG_SYMCAT0(x,y) 

# define TMP_DBG_FLAG volatile bool TMP_DBG_FLAG_SYMCAT(dbg_flag_,__LINE__) = false 
#else 
# define TMP_DBG_FLAG false 
#endif 
Problemi correlati