Antworten:
Präprozessor-Makros sind nur Substitutionsmuster, die auf Ihren Code angewendet werden. Sie können fast überall in Ihrem Code verwendet werden, da sie vor Beginn der Kompilierung durch ihre Erweiterungen ersetzt werden.
Inline-Funktionen sind tatsächliche Funktionen, deren Körper direkt in ihre Anrufstelle injiziert wird. Sie können nur verwendet werden, wenn ein Funktionsaufruf angemessen ist.
Wenn Sie nun Makros oder Inline-Funktionen in einem funktionsähnlichen Kontext verwenden möchten, beachten Sie Folgendes:
Erstens sind die Präprozessor-Makros nur "Kopieren Einfügen" im Code vor der Kompilierung. Es findet also keine Typprüfung statt und es können einige Nebenwirkungen auftreten
Zum Beispiel, wenn Sie 2 Werte vergleichen möchten:
#define max(a,b) ((a<b)?b:a)
Die Nebenwirkungen treten beispielsweise bei Verwendung max(a++,b++)
auf ( a
oder b
werden zweimal erhöht). Verwenden Sie stattdessen (zum Beispiel)
inline int max( int a, int b) { return ((a<b)?b:a); }
max(fibonacci(100), factorial(10000))
Die Inline-Funktion wird vom Compiler erweitert, während die Makros vom Präprozessor erweitert werden. Dies ist lediglich eine Textsubstitution
Während des Makroaufrufs findet keine Typprüfung statt, während die Typprüfung während des Funktionsaufrufs erfolgt.
Unerwünschte Ergebnisse und Ineffizienzen können während der Makroerweiterung aufgrund einer Neubewertung von Argumenten und der Reihenfolge der Operationen auftreten. Beispielsweise
#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);
würde dazu führen
int i = 5, j = ((i++)>(0) ? (i++) : (0));
Die Makroargumente werden vor der Makroerweiterung nicht ausgewertet
#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`
Das Schlüsselwort return kann in Makros nicht verwendet werden, um Werte zurückzugeben, wie im Fall von Funktionen.
Inline-Funktionen können überlastet werden
Die an Makros übergebenen Token können mit dem Operator ## verkettet werden, der als Token-Pasting-Operator bezeichnet wird.
Makros werden im Allgemeinen für die Wiederverwendung von Code verwendet, wobei Inline-Funktionen verwendet werden, um den Zeitaufwand (überschüssige Zeit) während des Funktionsaufrufs zu vermeiden (um einen Sprung zu einer Unterroutine zu vermeiden).
Der Hauptunterschied ist die Typprüfung. Der Compiler prüft, ob das, was Sie als Eingabewerte übergeben, vom Typ ist, der an die Funktion übergeben werden kann. Dies gilt nicht für Präprozessor-Makros. Sie werden vor jeder Typprüfung erweitert und können schwerwiegende und schwer zu erkennende Fehler verursachen.
Hier sind einige andere weniger offensichtliche Punkte umrissen.
Um einen weiteren Unterschied zu den bereits angegebenen hinzuzufügen: Sie können #define
im Debugger nicht durch eine , sondern durch eine Inline-Funktion gehen.
Makros ignorieren Namespaces. Und das macht sie böse.
Inline-Funktionen ähneln Makros (da der Funktionscode zum Zeitpunkt des Aufrufs zur Kompilierungszeit erweitert wird), Inline-Funktionen werden vom Compiler analysiert, während Makros vom Präprozessor erweitert werden. Infolgedessen gibt es mehrere wichtige Unterschiede:
In einigen Fällen können Ausdrücke, die als Argumente an Makros übergeben werden, mehrmals ausgewertet werden. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx
Makros werden vor der Kompilierung erweitert. Sie können sie nicht zum Debuggen verwenden, aber Sie können Inline-Funktionen verwenden.
- guter Artikel : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1
;;
Eine Inline-Funktion behält die Wertesemantik bei, während ein Präprozessor-Makro nur die Syntax kopiert. Wenn Sie das Argument mehrmals verwenden, können mit einem Präprozessor-Makro sehr subtile Fehler auftreten. Wenn das Argument beispielsweise eine Mutation wie "i ++" enthält, die zweimal ausgeführt wird, ist dies eine ziemliche Überraschung. Eine Inline-Funktion hat dieses Problem nicht.
Eine Inline-Funktion verhält sich syntaktisch wie eine normale Funktion und bietet Typensicherheit sowie einen Bereich für lokale Funktionsvariablen und den Zugriff auf Klassenmitglieder, wenn es sich um eine Methode handelt. Auch beim Aufrufen von Inline-Methoden müssen Sie private / geschützte Einschränkungen einhalten.
Um den Unterschied zwischen Makro- und Inline-Funktion zu erkennen , sollten wir zunächst wissen, was genau sie sind und wann wir sie verwenden sollten.
FUNKTIONEN :
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
Mit Funktionsaufrufen ist Overhead verbunden, da die Funktion nach Abschluss der Ausführung wissen muss, wohin sie zurückkehren muss, und den Wert auch im Stapelspeicher speichern muss.
Für kleine Anwendungen ist dies kein Problem, aber nehmen wir ein Beispiel für Finanzanwendungen, bei denen jede Sekunde Tausende von Transaktionen ausgeführt werden. Wir können keine Funktionsaufrufe ausführen.
MAKROS:
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
int result = Quadrat (x * x)
Mit Makros sind jedoch Fehler verbunden.
#define Square(x) x*x
int main() {
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Hier ist die Ausgabe 11 nicht 36 .
INLINE-FUNKTIONEN :
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;
}
Ausgabe 36
Das Inline-Schlüsselwort fordert den Compiler auf, den Funktionsaufruf durch den Hauptteil der Funktion zu ersetzen. Hier ist die Ausgabe korrekt, da zuerst der Ausdruck ausgewertet und dann übergeben wird. Dadurch wird der Aufwand für Funktionsaufrufe verringert, da die Rücksprungadresse und der Stapel nicht gespeichert werden müssen Für Funktionsargumente ist kein Speicher erforderlich.
Vergleich zwischen Makros und Inline-Funktionen:
FAZIT:
Inline-Funktionen sind manchmal nützlicher als Makros, da sie die Leistung verbessern, sicher zu verwenden sind und den Aufwand für Funktionsaufrufe verringern. Es ist nur eine Anfrage an den Compiler, bestimmte Funktionen werden nicht wie folgt eingefügt:
Das ist eine gute Sache, denn das ist immer dann, wenn der Compiler denkt, dass es am besten ist, die Dinge anders zu machen.
In GCC (bei anderen bin ich mir nicht sicher) ist das Deklarieren einer Funktion inline nur ein Hinweis für den Compiler. Am Ende des Tages muss der Compiler noch entscheiden, ob er den Funktionskörper enthält, wenn er aufgerufen wird.
Der Unterschied zwischen Inline-Funktionen und Präprozessormakros ist relativ groß. Präprozessor-Makros sind letztendlich nur Textersetzung. Sie geben dem Compiler viel von der Möglichkeit auf, die Typprüfung der Argumente und den Rückgabetyp zu überprüfen. Die Bewertung der Argumente ist sehr unterschiedlich (wenn die Ausdrücke, die Sie an die Funktionen übergeben, Nebenwirkungen haben, macht das Debuggen sehr viel Spaß). Es gibt subtile Unterschiede, wo Funktionen und Makros verwendet werden können. Zum Beispiel, wenn ich hätte:
#define MACRO_FUNC(X) ...
Wobei MACRO_FUNC offensichtlich den Hauptteil der Funktion definiert. Besondere Vorsicht ist geboten, damit es in allen Fällen korrekt ausgeführt wird. Eine Funktion kann verwendet werden. Beispielsweise würde ein schlecht geschriebener MACRO_FUNC einen Fehler in verursachen
if(MACRO_FUNC(y)) {
...body
}
Eine normale Funktion könnte dort problemlos verwendet werden.
Aus Sicht der Codierung ist eine Inline-Funktion wie eine Funktion. Somit sind die Unterschiede zwischen einer Inline-Funktion und einem Makro dieselben wie die Unterschiede zwischen einer Funktion und einem Makro.
Aus der Sicht des Kompilierens ähnelt eine Inline-Funktion einem Makro. Es wird direkt in den Code eingefügt und nicht aufgerufen.
Im Allgemeinen sollten Sie Inline-Funktionen als reguläre Funktionen mit geringfügigen Optimierungen betrachten. Wie bei den meisten Optimierungen muss der Compiler entscheiden, ob er sie tatsächlich anwenden möchte. Oft ignoriert der Compiler aus verschiedenen Gründen alle Versuche des Programmierers, eine Funktion zu integrieren.
Inline-Funktionen verhalten sich wie ein Funktionsaufruf, wenn eine iterative oder rekursive Anweisung darin vorhanden ist, um die wiederholte Ausführung von Anweisungen zu verhindern. Es ist sehr hilfreich, den Gesamtspeicher Ihres Programms zu speichern.
#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;
}
Makros sind normalerweise schneller als Funktionen, da sie keinen tatsächlichen Funktionsaufruf-Overhead beinhalten.
Einige Nachteile von Makros: Es gibt keine Typprüfung. Schwierig zu debuggen, da sie einen einfachen Ersatz verursachen. Makro hat keinen Namespace, daher kann ein Makro in einem Codeabschnitt einen anderen Abschnitt beeinflussen. Makros können Nebenwirkungen verursachen, wie im obigen Beispiel CUBE () gezeigt.
Makros sind normalerweise einzeilig. Sie können jedoch aus mehr als einer Zeile bestehen. In Funktionen gibt es keine derartigen Einschränkungen.
#define TWO_N(n) 2 << n
und dann cout << CUBE(TWO_N(3 + 1)) << endl;
? (Es ist besser, die Ausgabezeilen zu beenden, endl
als sie damit zu beginnen.)