#define
ist ein Präprozessor-Werkzeug und hat Makrosemantik. Beachten Sie dies, wenn max(a,b)
ein Makro ist, das als
#define max(a,b) ((a)>(b)?(a):(b))
:
Beispiel 1:
val = max(100, GetBloodSample(BS_LDL))
würde zusätzliches unschuldiges Blut verschütten, weil die Funktion tatsächlich zweimal aufgerufen wird. Dies kann zu erheblichen Leistungsunterschieden bei realen Anwendungen führen.
Beispiel 2:
val = max(3, schroedingerCat.GetNumPaws())
Dies zeigt einen schwerwiegenden Unterschied in der Programmlogik , da dieser unerwartet eine Zahl zurückgeben kann, die kleiner als 3 ist - etwas, das der Benutzer nicht erwartet.
Beispiel 3:
val = max(x, y++)
könnte y
mehr als einmal inkrementieren.
Mit Inline-Funktionen wird keiner von diesen passieren.
Der Hauptgrund ist, dass das Makrokonzept die Transparenz der Implementierung (textueller Codeaustausch) und Inline auf die richtigen Sprachkonzepte abzielt, wodurch die Aufrufsemantik für den Benutzer transparenter wird.
Funktionen (ob inline
oder nicht) und Makros erfüllen unterschiedliche Zwecke. Ihr Unterschied sollte nicht als ideologisch betrachtet werden, wie manche es zu nehmen scheinen, und was noch wichtiger ist, sie können gut zusammenarbeiten.
Makros sind Textersetzungen, die zum Zeitpunkt der Kompilierung durchgeführt werden, und sie können Dinge wie
tun %Vor%gibt Ihnen einen Kompilierzeitausdruck darüber, ob ein ganzzahliger Typ signiert ist oder nicht. Das heißt, sie werden idealerweise verwendet, wenn der Typ eines Ausdrucks nicht bekannt ist (bei der Definition) und Sie etwas dagegen tun möchten. Auf der anderen Seite besteht die Gefahr bei Makros darin, dass ihre Argumente mehrmals ausgewertet werden können, was aufgrund von Nebenwirkungen schlecht ist.
Funktionen ( inline
) auf der anderen Seite sind getippt, was sie strenger oder negativer formuliert weniger flexibel macht. Betrachten Sie die Funktionen
Der erste implementiert die triviale Funktion abs
für einen vorzeichenlosen ganzzahligen Typ. Die zweite implementiert es für einen signierten Typ. (Ja, es braucht ein nicht unterzeichnet als Argument, das ist für den Zweck.)
Wir können diese mit jedem ganzzahligen Typ verwenden. Aber der Rückgabetyp wird immer die größte Breite haben und es gibt eine gewisse Schwierigkeit zu wissen, wie man zwischen den beiden wählen kann.
Jetzt mit dem folgenden Makro
%Vor%Wir haben ein
implementiert (Nun, ich gebe zu, dass dies mit abs
ein bisschen künstlich ist, aber ich hoffe, Sie bekommen das Bild.)
Makros (erstellt mit #define
) werden immer wie geschrieben ersetzt und können Probleme bei der doppelten Auswertung haben.
inline
dagegen ist rein beratend - der Compiler kann es ignorieren. Unter dem C99-Standard kann eine inline
-Funktion auch eine externe Verknüpfung haben, die eine Funktionsdefinition erzeugt, mit der verlinkt werden kann.
Nun, eine mehrzeilige #define
ist schwieriger zu schreiben und zu bearbeiten als eine Inline-Funktion. Sie können eine Inline-Funktion wie jede normale Funktion definieren und Variablen ohne Probleme definieren. Stellen Sie sich vor, Sie möchten einen Code-Block mehrmals innerhalb einer anderen Funktion aufrufen, und dieser Code-Block benötigt seine eigenen Variablen: Es ist einfacher mit Inline-Funktionen zu arbeiten (Ja, Sie können dies mit #defines und do { ... } while (0);
tun, aber Sie sind es muss darüber nachdenken).
Außerdem erhalten Sie bei aktiviertem Debugging normalerweise einen "simulierten" Stack-Frame für Inline-Funktionen, der das Debuggen manchmal einfacher macht (zumindest erhalten Sie dies, wenn Sie mit% cc_de% von gcc kompilieren / verknüpfen und mit GDB debuggen). IIRC). Sie können Haltepunkte innerhalb Ihrer Inline-Funktion platzieren.
Abgesehen davon sollte das Ergebnis fast identisch sein, AFAIK.
Funktionsähnliche Makros geben Ihnen an der Stelle, an der sie definiert sind, absolut keine Plausibilitätsprüfung. Wenn Sie ein Makro vermasseln, wird es an einem Ort gut funktionieren und woanders kaputt gehen, und Sie werden nicht wissen, warum, bis Sie mehrere Stunden Arbeit / Schlaf verloren haben. Funktionsähnliche Makros arbeiten nicht mit Daten, sie arbeiten mit Quellcode. Manchmal ist das gut, wenn Sie beispielsweise wiederverwendbare Debug-Anweisungen verwenden möchten, die FILE und LINE Builtins verwenden, aber meistens auch mit einem Inline-Befehl Funktion, die genau wie jede andere Funktion auf die Syntax am Definitionspunkt überprüft wird.
Tags und Links c inline c-preprocessor