2009-10-15 11 views
9

According to the C FAQ, ci sono fondamentalmente 3 metodi pratici di codice "inlining" in C:Pro e contro dei diversi metodi macro funzione/linea in C

#define MACRO(arg1, arg2) do { \ 
    /* declarations */ \ 
    stmt1; \ 
    stmt2; \ 
    /* ... */ \ 
    } while(0) /* (no trailing ;) */ 

o

#define FUNC(arg1, arg2) (expr1, expr2, expr3) 

Per chiarire questo , gli argomenti vengono utilizzati nelle espressioni e l'operatore virgola restituisce il valore dell'ultima espressione.

o

utilizzando la dichiarazione inline che è supportato come extension to gcc and in the c99 standard.

Il metodo do { ... } while (0) è ampiamente utilizzato nel kernel di Linux, ma non ho riscontrato gli altri due metodi molto spesso se non del tutto.

Mi riferisco in particolare alle "funzioni" a più istruzioni, non a quelle a singola istruzione come MAX o MIN.

Quali sono i pro e i contro di ciascun metodo, e perché scegliere l'uno rispetto all'altro in varie situazioni?

+0

L'esempio medio non ha molto senso, la macro accetta argomenti denominati arg1 e arg2 e nel corpo macro si usano expr1, expr2 ed expr3 ? – unwind

+1

Ha senso, perché quelli di 'argN' possono essere annidati in sottoespressioni sul lato destro. Come '(arg1^= arg2, arg2^= arg1, arg1^= arg2)', penso. –

+3

A meno che tu non abbia misurato il tuo codice e sappia che devi ottimizzare, non preoccuparti: scrivi le normali funzioni per tutto. – pmg

risposta

16

Parlando che l'uso specifico di macro, vale a dire le macro che agiscono come "funzioni", mi piacerebbe menzionare i seguenti vantaggi di macro che non si possono avere in una funzione inline:

Pigro valutazione argomento. Ad esempio, una macro come questa

#define SELECT(f, a, b) ((f) ? (a) : (b)) 

conserverebbe le proprietà pigri valutazione argomento dell'operatore ternario: solo il parametro selezionato viene analizzato, mentre l'altra no. Un semplice analogo di funzione inline valuterà in anticipo entrambi gli argomenti, facendo così un lavoro superfluo.

Accesso al contesto. I macro possono essere utilizzati per implementare alcune somiglianze di "funzioni locali", ovvero parti di codice ripetitive che hanno accesso alla variabile locale e ai parametri della funzione di chiusura.

Tipo indipendenza (e parametri tipo). I macro consentono di scrivere "funzioni" indipendenti dal tipo (vedi esempio precedente). E nel caso in cui non è possibile eliminare la dipendenza dal tipo, è possibile passare i tipi come parametri alla macro.

Le proprietà di cui sopra delle macro, che ho presentato come i loro professionisti, potrebbero essere utilizzate in modo errato per portare a gravi fallimenti (e quindi potrebbero essere presentati anche come contro). Ma questo è qualcosa che si può dire di molte caratteristiche linguistiche in C.

+0

+1 Questi sono tutti i punti positivi. –

+1

In un esempio come #define MAX (A, B) ((A)> (B)? (A) :(B)) se A o B include un'azione (come i ++), è anche peggio perché sarà valutato due volte. – eyalm

+0

@AndreyT: Forse potresti precisare alcuni di questi svantaggi? –

0

L'unico pro che riesco a vedere utilizzando uno dei costrutti è per rendere più rapido il codice.

Quindi, scegliere l'unico metodo che fornisce il codice più veloce!

Se è lo stesso, quindi lo trovo più leggibile

  1. una funzione di 'standard'
  2. un inline funzione
  3. le #define ... do {} while(0) approccio
  4. la macro con separati da virgola espressioni
5

Un professionista dell'utilizzo della parola chiave inline è che si ottiene un controllo dei tipi di gli argomenti tramite la funzione prototipo. Usando le macro non si ottiene nulla del genere, quindi le macro sono suscettibili di creare strani errori se si inseriscono elementi del tipo sbagliato in essi. (Non altrettanto orribile come errori di modello in C++ però.)

Uno dei vantaggi dell'uso delle macro è che puoi fare cose funky come le concatenazioni e trasformare l'argomento macro in una stringa usando #arg. Un altro vantaggio dell'utilizzo di macro di preprocessore è che puoi facilmente verificare come si espandono utilizzando cpp per svolgerli. In questo modo esegui il debug di questi errori.

Un altro punto utile delle funzioni macro definite è che è possibile inserire un'istruzione return per arrestare la funzione genitore, se necessario. Con una funzione inline è necessario restituire un valore e quindi controllare il valore restituito.

+0

In realtà, i tipi di funzioni desiderati erano disponibili in C. In questo modo si potrebbe ottenere la flessibilità dei macro con il tipo di sicurezza delle funzioni. –

+0

@ RobertS.Barnes, si chiama C per un motivo – Pacerier