2013-06-09 12 views
6

Non ho mai lavorato con #if, #ifdef, #ifndef, #else, #elif e #endif.Vantaggi del condizionale-preprocessore oltre istruzioni condizionali

Mentre stavo esaminando alcuni codici sorgente, ho trovato un ampio uso di queste direttive. Ha fatto qualche lettura sui preprocessori condizionali ma non ha trovato alcun indizio come in che modo sono diversi dalle normali istruzioni condizionali. Così mi chiedevo che cosa è il vantaggio di codice seguente:

#include<iostream> 
int main() 
{ 
    int i = 0; 

    #if i == 0 
     std::cout<<"This"; 
    #else 
     std::cout<<"That"; 
    #endif 
    return 0; 
} 

su questo:

#include<iostream> 
int main() 
{ 
    int i = 0; 

    if (i == 0) 
     std::cout<<"This"; 
    else 
     std::cout<<"That"; 
    return 0; 
} 

Inoltre, quando da usare/non utilizzo condizionale-preprocessore?

+1

Per i primi, 'if' viene valutato in fase di esecuzione e' # if' viene valutato prima della compilazione. – Aiias

+0

http://stackoverflow.com/help/dont-ask – xaxxon

+4

@xaxxon: Puoi spiegare in che modo quel collegamento è rilevante? – Blender

risposta

3

Il preprocessore condizionale non funziona come nel primo esempio.

Sta funzionando con le costanti, vedi? Al momento della compilazione, esamina le varie condizioni e inserisce/omette il codice sorgente in base ad esso.

Ad esempio:

#define HAS_COMPARISON 

int main() { 
    #ifdef HAS_COMPARISON 
     int i = 0; 
     if(i == 0) std::cout << "This"; 
     else 
    #else 
     std::cout << "That"; 
    #endif 
} 

Con il set define, imposterà la variabile i ed eseguire il confronto ... in breve, il risultato sarà This. Se il commento è definito, l'intero blocco non sarà presente nel programma, il che significa che emetterà sempre That, senza mai impostare la variabile o eseguire il confronto.

Questo è l'uso più comune delle definizioni del preprocessore. È inoltre possibile definire valori e confrontarli con comportamenti variabili con la stessa definizione, ma questo è un altro problema.

Ancora una volta: il preprocessore condizionale viene valutato al momento della compilazione, le condizioni variabili vengono valutate in fase di esecuzione.

+0

~ correggimi se ho torto, è come se ** HAS_COMPARISON ** sia impostato a 0 before-compilation quindi il compilatore elimina il blocco all'interno di _ # else_ & _ # endif_ come fa per _dead code delete_. – ikis

+0

@iKishore Il * preprocessore * rilascia il codice prima che il compilatore lo veda, il che è importante perché il codice che è stato condizionato potrebbe non essere compilato/causare un errore quando il compilatore lo vede (ad esempio a causa di errori di tipo o funzioni mancanti). – delnan

+1

@iKishore No, hai ragione. Se è impostato su QUALSIASI valore, '# else' viene eliminato, mentre se' # define' viene rimosso dal codice, tutto ciò che va da '# ifdef' a' # else' viene eliminato. –

1

La compilazione condizionale significa che il codice ifdef-out non è mai effettivamente nell'applicazione finale collegata. Usare semplicemente le condizioni linguistiche significa che entrambi i rami sono nel codice finale rendendolo più grande e potenzialmente più difficile da testare ecc.

Utilizzare #ifdef ecc. Quando si sa in fase di compilazione cosa è richiesto. Le condizioni linguistiche vengono utilizzate quando non si conosce ciò che è necessario fino al runtime.

1

i vantaggi del preprocessore è che il codice viene espulso. Non viene compilato (richiede tempo) e non genera codice macchina che verrà caricato nella ram. Se la decisione è in un ciclo MOLTO stretto, molte volte, potrebbe esserci un miglioramento della velocità. Non dare per scontato che questo sia importante, a meno che tu non lo decida realmente.

Gli svantaggi del preprocessore è che ovviamente devi conoscere la risposta al momento della compilazione. Il codice sorgente ora contiene un sacco di codice che potrebbe non essere mai eseguito. Diventa più difficile rintracciare per un umano perché è spesso difficile determinare quali sarebbero stati quei valori in fase di compilazione.

+0

In realtà, se la condizione è una costante in fase di compilazione (e abbastanza semplice che il preprocessore è un'opzione) il compilatore è solitamente in grado di dedurlo e rimuovere il codice morto se è testato con 'se'. – delnan

+0

Abbastanza vero. È sempre bene tenere a mente quanto siano intelligenti i compilatori. Le persone spesso scrivono codice confuso per provare a fare un'ottimizzazione prematura e poi realizzano che non lo hanno reso più veloce ed è anche più difficile da leggere/mantenere. – xaxxon

4

L'esempio che hai mostrato non sembra utile a causa della mancanza di altre informazioni. Ma ecco un esempio che è utile #if.

#if OS == LINUX 
//do something 
#elif OS == SOLARIS 
//do something else 
#else 
// 
#endif 

La chiave è che #if viene valutata in fase di compilazione, ma if viene valutato quando programma viene eseguito.

#if BYTE_ORDER == LITTLE_ENDIAN 
//do something 
#else 
//do something else 
#endif 
2

L'uso delle direttive del preprocessore in questo caso non è del tutto utile. Ma l'uso di queste direttive per il preprocessore è utile in molti altri casi.

Queste direttive del preprocessore possono essere utilizzate per la compilazione condizionale. per esempio. Se alcuni programmi devono essere sviluppati per piattaforme multiple, le costanti specifiche della piattaforma possono avere valori. È possibile modificare la compilazione di questi valori specifici per la piattaforma mentre l'intero codice può essere mantenuto come un'unica grande entità.

Questi sono utili anche durante il debug. Le unità di test possono essere compilate nel codice ed eseguite usando queste compilazioni condizionali durante il debug e possono essere fermate dalla compilazione usando queste.