Risposte:
Le macro del preprocessore sono solo modelli di sostituzione applicati al codice. Possono essere utilizzati quasi ovunque nel codice perché vengono sostituiti con le loro espansioni prima che inizi la compilazione.
Le funzioni inline sono funzioni effettive il cui corpo viene iniettato direttamente nel sito di chiamata. Possono essere utilizzati solo dove una chiamata di funzione è appropriata.
Ora, per quanto riguarda l'utilizzo di macro e funzioni inline in un contesto simile a una funzione, tieni presente che:
Innanzitutto, le macro del preprocessore sono semplicemente "copia incolla" nel codice prima della compilazione. Quindi non c'è controllo del tipo e possono comparire alcuni effetti collaterali
Ad esempio, se desideri confrontare 2 valori:
#define max(a,b) ((a<b)?b:a)
Gli effetti collaterali compaiono se si utilizza max(a++,b++)
ad esempio ( a
o b
verranno incrementati due volte). Utilizza invece (ad esempio)
inline int max( int a, int b) { return ((a<b)?b:a); }
max(fibonacci(100), factorial(10000))
quello più grande verrà calcolato due volte :(
La funzione Inline viene espansa dal compilatore mentre le macro vengono espanse dal Preprocessore, che è mera sostituzione testuale.
Non vi è alcun controllo del tipo durante il richiamo della macro mentre il controllo del tipo viene eseguito durante la chiamata della funzione.
Risultati indesiderati e inefficienza possono verificarsi durante l'espansione della macro a causa della rivalutazione degli argomenti e dell'ordine delle operazioni. Per esempio
#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);
risulterebbe in
int i = 5, j = ((i++)>(0) ? (i++) : (0));
Gli argomenti macro non vengono valutati prima dell'espansione macro
#define MUL(a, b) a*b
int main()
{
// The macro is expended as 2 + 3 * 3 + 5, not as 5*8
printf("%d", MUL(2+3, 3+5));
return 0;
}
// Output: 16`
La parola chiave return non può essere utilizzata nelle macro per restituire valori come nel caso delle funzioni.
Le funzioni inline possono essere sovraccaricate
I token passati alle macro possono essere concatenati utilizzando l'operatore ## chiamato operatore Token-Pasing.
Le macro vengono generalmente utilizzate per il riutilizzo del codice in cui le funzioni inline vengono utilizzate per eliminare il sovraccarico di tempo (tempo in eccesso) durante la chiamata di funzione (evitando il salto a una subroutine).
La differenza fondamentale è il controllo del tipo. Il compilatore verificherà se ciò che si passa come valori di input è di tipi che possono essere passati alla funzione. Questo non è vero con le macro del preprocessore: vengono espanse prima di qualsiasi controllo del tipo e ciò può causare bug gravi e difficili da rilevare.
Qui ci sono molti altri punti meno ovvi delineati.
Per aggiungere un'altra differenza a quelle già fornite: non è possibile eseguire il passaggio a #define
nel debugger, ma è possibile eseguire una funzione inline.
Le macro ignorano gli spazi dei nomi. E questo li rende malvagi.
le funzioni inline sono simili alle macro (poiché il codice della funzione viene espanso nel punto della chiamata in fase di compilazione), le funzioni inline vengono analizzate dal compilatore, mentre le macro vengono espanse dal preprocessore. Di conseguenza, ci sono molte importanti differenze:
In alcuni casi, le espressioni passate come argomenti alle macro possono essere valutate più di una volta. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx
le macro vengono espanse in fase di pre-compilazione, non è possibile utilizzarle per il debug, ma è possibile utilizzare funzioni inline.
- buon articolo : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1
;
Una funzione inline manterrà la semantica del valore, mentre una macro del preprocessore copia solo la sintassi. Puoi ottenere bug molto sottili con una macro del preprocessore se usi l'argomento più volte - per esempio se l'argomento contiene una mutazione come "i ++", averla eseguita due volte è una sorpresa. Una funzione inline non avrà questo problema.
Una funzione inline si comporta sintatticamente proprio come una normale funzione, fornendo l'indipendenza dai tipi e un ambito per le variabili locali della funzione e l'accesso ai membri della classe se si tratta di un metodo. Inoltre, quando si chiamano metodi inline, è necessario rispettare le restrizioni private / protette.
Per conoscere la differenza tra macro e funzione inline , in primo luogo dovremmo sapere cosa sono esattamente e quando dovremmo usarli.
FUNZIONI :
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
Alle chiamate di funzione è associato un sovraccarico, poiché dopo che la funzione termina l'esecuzione deve sapere dove deve tornare e deve anche memorizzare il valore nella memoria dello stack.
Per le piccole applicazioni non sarà un problema, ma prendiamo un esempio di applicazioni finanziarie in cui avvengono migliaia di transazioni ogni secondo, non possiamo andare con le chiamate di funzione.
MACRO:
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
int risultato = Quadrato (x * x)
Ma alle macro sono associati dei bug.
#define Square(x) x*x
int main() {
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Qui l'uscita è 11 non 36 .
FUNZIONI IN LINEA :
inline int Square(int x) {
return x * x;
}
int main() {
using namespace std;
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Uscita 36
La parola chiave inline richiede al compilatore di sostituire la chiamata di funzione con il corpo della funzione, qui l'output è corretto perché prima valuta l'espressione e poi viene passato Riduce l'overhead della chiamata di funzione poiché non è necessario memorizzare l'indirizzo di ritorno e lo stack la memoria non è richiesta per gli argomenti della funzione.
Confronto tra macro e funzioni inline:
CONCLUSIONE:
Le funzioni inline a volte sono più utili delle macro, poiché migliora le prestazioni ed è sicuro da usare e riduce anche il sovraccarico delle chiamate di funzione. È solo una richiesta al compilatore, alcune funzioni non saranno inline come:
il che è una buona cosa, perché è ogni volta che il compilatore pensa che sia meglio fare le cose in un altro modo.
In GCC (non sono sicuro degli altri), dichiarare una funzione inline è solo un suggerimento per il compilatore. Alla fine della giornata spetta ancora al compilatore decidere se includere o meno il corpo della funzione ogni volta che viene chiamata.
La differenza tra le funzioni in linea e le macro del preprocessore è relativamente grande. Le macro del preprocessore sono solo la sostituzione del testo alla fine della giornata. Rinunci a molte delle possibilità per il compilatore di eseguire il controllo sul controllo del tipo sugli argomenti e sul tipo restituito. La valutazione degli argomenti è molto diversa (se le espressioni che passi alle funzioni hanno effetti collaterali, ti divertirai molto a fare il debug). Esistono sottili differenze su dove è possibile utilizzare le funzioni e le macro. Ad esempio se avessi:
#define MACRO_FUNC(X) ...
Dove MACRO_FUNC definisce ovviamente il corpo della funzione. È necessario prestare particolare attenzione affinché funzioni correttamente in tutti i casi può essere utilizzata una funzione, ad esempio una MACRO_FUNC scritta male causerebbe un errore in
if(MACRO_FUNC(y)) {
...body
}
Una funzione normale potrebbe essere utilizzata senza problemi lì.
Dal punto di vista della codifica, una funzione inline è come una funzione. Pertanto, le differenze tra una funzione inline e una macro sono le stesse delle differenze tra una funzione e una macro.
Dal punto di vista della compilazione, una funzione inline è simile a una macro. Viene iniettato direttamente nel codice, non chiamato.
In generale, dovresti considerare le funzioni inline come funzioni regolari con qualche ottimizzazione minore mescolata. E come la maggior parte delle ottimizzazioni, spetta al compilatore decidere se effettivamente si preoccupa di applicarle. Spesso il compilatore ignorerà felicemente qualsiasi tentativo da parte del programmatore di incorporare una funzione, per vari motivi.
le funzioni inline si comporteranno come una chiamata di funzione se in essa esiste un'istruzione iterativa o ricorsiva, in modo da impedire l'esecuzione ripetuta di istruzioni. È molto utile salvare la memoria complessiva del programma.
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{
return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases.
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
return a*a*a;
}
int main()
{
cout<<NUMBER<<endl<<number()<<endl;
cout<<CUBE(1+3); //Unexpected output 10
cout<<endl<<cube(1+3);// As expected 64
return 0;
}
Le macro sono in genere più veloci delle funzioni in quanto non implicano l'effettivo sovraccarico delle chiamate di funzione.
Alcuni svantaggi delle macro: non c'è controllo del tipo Difficile da eseguire il debug in quanto causano una semplice sostituzione La macro non ha spazio dei nomi, quindi una macro in una sezione del codice può influenzare l'altra sezione. Le macro possono causare effetti collaterali come mostrato nell'esempio CUBE () sopra.
Le macro sono generalmente un rivestimento. Tuttavia, possono essere costituiti da più di una riga. Non ci sono tali vincoli nelle funzioni.
#define TWO_N(n) 2 << n
e poi cout << CUBE(TWO_N(3 + 1)) << endl;
? (È meglio terminare le righe di output endl
piuttosto che iniziarle.)