2010-08-24 16 views
8

Come dice il titolo; qual è la differenza nella pratica tra la parola chiave inline e la direttiva #define del preprocessore?Qual è la differenza nella pratica tra inline e #define?

+0

possibile duplicato del [funzioni inline vs preprocessore macro] (http (Beh, ammetto che fare questo con abs è un po 'artificiale, ma spero che si ottiene l'immagine.): // stackoverflow.com/questions/1137575/inline-functions-vs-preprocessor-macros) – jww

risposta

37

#define è uno strumento preprocessore e ha la semantica macro. Considerate questo, se max(a,b) è una macro definita come

#define max(a,b) ((a)>(b)?(a):(b)):

Ex 1:

val = max(100, GetBloodSample(BS_LDL)) sarebbe versare sangue in più innocente, perché la funzione sarà effettivamente chiamato due volte. Ciò potrebbe significare una significativa differenza di prestazioni per le applicazioni reali.

Es 2:

val = max(3, schroedingerCat.GetNumPaws()) Questo dimostra un grave differenza nella logica del programma, perché questo può restituire inaspettatamente un numero che è inferiore a 3 - qualcosa che l'utente non ci si aspetterebbe.

Ex 3:

val = max(x, y++) potrebbe incrementare più di una volta y.


Con funzioni in linea, nessuna di queste accadrà.

Il motivo principale è che il concetto di macro obiettivi la trasparenza di attuazione (codice testuale sostituire) e gli obiettivi in ​​linea concetti linguaggio corretto, rendendo la semantica invocazione più trasparente per l'utente.

+3

+1 Per l'esempio di spargimento di sangue – Tomas

+2

È necessario modificare 'shroedingerCat.GetNumPaws()' per essere una funzione C, non C++. – alternative

+0

Bene, la domanda riguarda C; è però più comune per le funzioni dei membri C++ restituire di volta in volta cose diverse, perché si basano naturalmente sullo stato del loro oggetto. –

1

macro (creati con #define) sono sempre sostituiti come scritto, e possono avere problemi di doppia valutazione.

inline d'altra parte, è puramente consultivo - il compilatore è libero di ignorarlo. Sotto lo standard C99, una funzione inline può anche avere linkage esterno, creando una definizione di funzione che può essere collegata contro.

1

Beh, un multi-linea di #define è più difficile da scrivere e modificare di una funzione inline. È possibile definire una funzione in linea come qualsiasi funzione normale e definire variabili senza problemi. Immagina di voler chiamare un blocco di codice più volte all'interno di un'altra funzione e che il blocco di codice ha bisogno di variabili proprie: è più facile da fare con le funzioni inline (sì, puoi farlo con #defines e do { ... } while (0); ma è qualcosa che devi Pensa a).

Inoltre, con abilitato il debug, normalmente si ottiene un "simulato" stack-frame per funzioni inline che potrebbe rendere più facile il debug a volte (almeno questo è quello che si ottiene quando si compila/link con gcc di -g e debug con GDB, IIRC). È possibile posizionare punti di interruzione all'interno della funzione inline.

parte che il risultato dovrebbe essere quasi identico, AFAIK.

0

Le macro di tipo funzione forniscono un controllo di integrità assolutamente zero nel punto in cui sono definite.Quando fai una cacca con una macro, funzionerà bene in un punto e sarà rotta da qualche altra parte, e non saprai perché fino a quando non avrai perso molte ore di lavoro/tempo di sonno. Le macro di tipo funzione non operano sui dati, operano su codice sorgente. A volte questo è buono, per esempio quando si vogliono istruzioni di debug riutilizzabili che usano i compilatori e LINE, ma la maggior parte delle volte può essere eseguito altrettanto bene con una funzione inline, che viene controllata per la sintassi al punto di definizione proprio come qualsiasi altra funzione.

2

Funzioni (sia inline o meno) e macro soddisfano diversi scopi. La loro differenza non dovrebbe essere vista come ideologica come alcuni sembrano prenderla, e ciò che è ancora più importante, possono funzionare bene insieme.

macro sono la sostituzione del testo che viene fatto al momento della compilazione e possono fare cose come

#define P99_ISSIGNED(T) ((T)-1 < (T)0) 

che ti dà un'espressione fase di compilazione o meno un tipo integrale è firmato o meno. Cioè, sono idealmente utilizzati quando il tipo di un'espressione non è noto (alla definizione) e si vuole fare qualcosa al riguardo. D'altra parte, il trabocchetto con le macro è che i loro argomenti possono essere valutati più volte, il che è negativo a causa degli effetti collaterali.

Le funzioni (inline) sull'altro sono digitate, il che le rende più rigide o, formulate in modo negativo, meno flessibili. Considerare le funzioni

inline uintmax_t absU(uintmax_t a) { return a; } 
inline uintmax_t absS(uintmax_t a) { 
    return (-a < a) ? -a : a; 
} 

Il primo implementa la funzione abs banale per un tipo intero senza segno. Il secondo lo implementa per un tipo firmato. (sì, ci vuole un argomento senza segno, questo è per scopo.)

Possiamo usarli con qualsiasi tipo di integrale. Ma il tipo di ritorno sarà sempre della larghezza maggiore e c'è una certa difficoltà nel sapere come scegliere tra i due.

Ora, con la seguente macro

#define ABS(T, A) ((T)(P99_ISSIGNED(T) ? absS : absU)(A)) 

abbiamo implementato una famiglia

  • di funzioni
  • che funziona per qualsiasi tipo integrale
  • che valuta il suo argomento solo una volta
  • per il quale verrà creato un compilatore recente e rispettabile Codice ottimale

Problemi correlati