Warum verwendet die C-Bibliothek Makros und Funktionen mit demselben Namen?

20

Ich lese gerade 'The Standard C Library' von PJ Plauger, was wirklich interessant ist. Das Buch erklärt nicht nur, wie die Bibliothek NUTZT wird, sondern auch, wie sie implementiert wird.

Ich habe den ctype.hAbschnitt gelesen und in der Kopfzeile sind die Funktionen als Makros UND Funktionen deklariert. Beispielsweise

int isdigit(int);

aber auch

#define isdigit(c) (_Ctype[(int)(c)] & _DI)

Ich verstehe nicht, warum beide verwendet werden?

Wenn ich versuche, meinen eigenen benutzerdefinierten ctypeHeader und meine Implementierung neu zu erstellen , kann ich nur dann erfolgreich kompilieren, wenn ich das Makro entferne (das Define auskommentiere).

Dieser Aspekt wurde im Buch nicht wirklich erklärt. Kann jemand bitte erklären?

user619818
quelle
Es gibt nichts im C-Standard, das einen Compiler zwingt, es als Makro zu implementieren. Das Makro ist höchstwahrscheinlich ein Rückstand aus früheren Zeiten, als C kein Inlining hatte. Ein intelligenter Compiler sollte jedoch in der Lage sein, diese Funktion bei Bedarf ohne ein explizites Inline-Schlüsselwort zu integrieren. Das funktionsähnliche Makro gibt es also nur, weil der Compiler von jemandem implementiert wurde, der keine brillanten Compiler-Fähigkeiten hatte.

Antworten:

23

Das Makro ist (mutmaßlich) effizienter, da es keinen Funktionsaufruf enthält. Es kann einfacher optimiert werden, da nur ein Zeiger-Offset-Lookup erforderlich ist.

Der Funktionsaufruf ermöglicht das Verknüpfen mit derselben Bibliothek, auch wenn das Programm ohne die Makrodefinition kompiliert wurde - wenn es mit einem anderen Header kompiliert wurde oder nur mit einer falschen Deklaration in der Quelldatei. Wenn Sie beispielsweise einen Compiler mit einer "verbesserten" Version von ctype.h haben, der kein Makro enthält, ist die Funktion zur Laufzeit noch verfügbar .

Wenn wir uns den Standard ansehen:

7.1.4 Nutzung von Bibliotheksfunktionen

Jede in einem Header deklarierte Funktion kann zusätzlich als funktionsähnliches Makro implementiert werden, das in dem Header definiert ist. Wenn eine Bibliotheksfunktion also explizit deklariert wird, wenn ihr Header enthalten ist, kann eine der unten gezeigten Techniken verwendet werden, um sicherzustellen, dass die Deklaration nicht erfolgt von einem solchen Makro betroffen. Jede Makrodefinition einer Funktion kann lokal unterdrückt werden, indem der Name der Funktion in Klammern eingeschlossen wird, da auf den Namen keine linke Klammer folgt, die die Erweiterung eines Makrofunktionsnamens angibt. Aus dem gleichen syntaktischen Grund ist es zulässig, die Adresse einer Bibliotheksfunktion zu übernehmen, auch wenn diese auch als Makro definiert ist.

Das heißt, wenn Sie schreiben:

int b = (isdigit)(c);

oder

int (*f)(int) = &isdigit;
int b = f(c);

dann rufen Sie die eigentliche Funktion auf, nicht das Makro. Sie können auch legal schreiben:

#undef isdigit
int b = isdigit(c);

oder (in einer Quelldatei nicht #include <ctype.h>direkt oder transitiv):

extern int isdigit(int);
int b = isdigit(c);
ecatmur
quelle
Wie könnte das Programm OHNE die Makrodefinition kompiliert werden?
user619818
@ user619818 extern int isdigit(int)zum Beispiel mit.
Ecatmur
Damit das klar ist, meinst du, dass der Benutzer kein #include <whatever> hat, sondern stattdessen int isdigit (int) hinzufügt; am Anfang der Implementierungsdatei. OK, lies einfach deine Antwort richtig durch.
user619818
Mit einer aufrufbaren Funktion (im Gegensatz zum eingebauten Makrocode) können auch andere Sprachen wie Python und Perl mit diesen Funktionen
interagieren