In C habe ich keine Auswirkung des extern
vor der Funktionsdeklaration verwendeten Schlüsselworts festgestellt. Zuerst dachte ich, dass Sie beim Definieren extern int f();
in einer einzelnen Datei gezwungen sind, diese außerhalb des Dateibereichs zu implementieren. Ich fand jedoch heraus, dass beide:
extern int f();
int f() {return 0;}
und
extern int f() {return 0;}
Kompilieren Sie ganz gut, ohne Warnungen von gcc. Ich habe benutzt gcc -Wall -ansi
; es würde nicht einmal //
Kommentare akzeptieren .
Gibt es irgendwelche Auswirkungen für die Verwendung extern
vor Funktionsdefinitionen ? Oder ist es nur ein optionales Schlüsselwort ohne Nebenwirkungen für Funktionen?
Im letzteren Fall verstehe ich nicht, warum die Standarddesigner beschlossen haben, die Grammatik mit überflüssigen Schlüsselwörtern zu verunreinigen.
EDIT: Um zu klären, ich weiß , dass es Verwendung für extern
Variablen, aber ich frage nur extern
in Funktionen .
Antworten:
Wir haben zwei Dateien, foo.c und bar.c.
Hier ist foo.c
Hier ist bar.c
Wie Sie sehen können, haben wir keinen gemeinsamen Header zwischen foo.c und bar.c, jedoch benötigt bar.c etwas, das in foo.c deklariert ist, wenn es verknüpft ist, und foo.c benötigt eine Funktion von bar.c, wenn es verknüpft ist.
Wenn Sie 'extern' verwenden, teilen Sie dem Compiler mit, dass alles, was folgt, zum Zeitpunkt der Verknüpfung gefunden wird (nicht statisch). Reservieren Sie im aktuellen Pass nichts dafür, da es später angetroffen wird. Funktionen und Variablen werden in dieser Hinsicht gleich behandelt.
Dies ist sehr nützlich, wenn Sie einige globale Elemente zwischen Modulen teilen müssen und diese nicht in einen Header einfügen / initialisieren möchten.
Technisch gesehen ist jede Funktion in einem öffentlichen Bibliotheksheader "extern", die Kennzeichnung als solche hat jedoch je nach Compiler nur sehr geringe oder gar keine Vorteile. Die meisten Compiler können das selbst herausfinden. Wie Sie sehen, sind diese Funktionen tatsächlich woanders definiert.
Im obigen Beispiel würde main () hallo world nur einmal drucken, aber weiterhin bar_function () eingeben. Beachten Sie auch, dass bar_function () in diesem Beispiel nicht zurückgegeben wird (da es sich nur um ein einfaches Beispiel handelt). Stellen Sie sich vor, stop_now wird geändert, wenn ein Signal bedient wird (daher flüchtig), wenn dies nicht praktisch genug erscheint.
Externe sind sehr nützlich für Dinge wie Signalhandler, einen Mutex, den Sie nicht in einen Header oder eine Struktur einfügen möchten usw. Die meisten Compiler optimieren, um sicherzustellen, dass sie keinen Speicher für externe Objekte reservieren, da sie diese kennen Ich werde es in dem Modul reservieren, in dem das Objekt definiert ist. Es macht jedoch wenig Sinn, es mit modernen Compilern zu spezifizieren, wenn öffentliche Funktionen prototypisiert werden.
Hoffentlich hilft das :)
quelle
bar.c
und der Deklaration in erhaltenfoo.c
. Wenn die Funktion in deklariert istfoo.h
und beide Dateien enthaltenfoo.h
, erzwingt der Header die Konsistenz zwischen den beiden Quelldateien. Wenn ohne sie die Definition vonbar_function
inbar.c
geändert wird, aber die Deklaration infoo.c
nicht geändert wird, laufen die Dinge zur Laufzeit schief. Der Compiler kann das Problem nicht erkennen. Wenn ein Header ordnungsgemäß verwendet wird, erkennt der Compiler das Problem.Soweit ich mich an den Standard erinnere, werden alle Funktionsdeklarationen standardmäßig als "extern" betrachtet, sodass keine explizite Angabe erforderlich ist.
Das macht dieses Schlüsselwort nicht unbrauchbar, da es auch mit Variablen verwendet werden kann (und in diesem Fall - es ist die einzige Lösung, um Verknüpfungsprobleme zu lösen). Aber mit den Funktionen - ja, es ist optional.
quelle
Sie müssen zwischen zwei getrennten Konzepten unterscheiden: Funktionsdefinition und Symboldeklaration. "extern" ist ein Verknüpfungsmodifikator, ein Hinweis an den Compiler, wo das Symbol definiert ist, auf das später Bezug genommen wird (der Hinweis lautet "nicht hier").
Wenn ich schreibe
Im Dateibereich (außerhalb eines Funktionsblocks) in einer C-Datei sagen Sie dann "Die Variable kann an anderer Stelle definiert werden".
ist sowohl eine Deklaration der Funktion f als auch eine Definition der Funktion f. Die Definition überschreibt in diesem Fall das Externe.
ist zunächst eine Erklärung, gefolgt von der Definition.
Die Verwendung von
extern
ist falsch, wenn Sie eine Dateibereichsvariable deklarieren und gleichzeitig definieren möchten. Beispielsweise,gibt je nach Compiler einen Fehler oder eine Warnung aus.
Die Verwendung von
extern
ist nützlich, wenn Sie die Definition einer Variablen explizit vermeiden möchten.Lassen Sie mich erklären:
Angenommen, die Datei ac enthält:
Die Datei ah enthält:
und die Datei bc enthält:
Das externe Element im Header ist nützlich, da es dem Compiler während der Verbindungsphase mitteilt, dass dies eine Deklaration und keine Definition ist. Wenn ich die Zeile in ac entferne, die i definiert, ihm Speicherplatz zuweist und ihm einen Wert zuweist, sollte das Programm nicht mit einer undefinierten Referenz kompiliert werden können. Dies teilt dem Entwickler mit, dass er auf eine Variable verwiesen, diese aber noch nicht definiert hat. Wenn ich andererseits das Schlüsselwort "extern" weglasse und die
int i = 2
Zeile entferne , wird das Programm immer noch kompiliert - ich werde mit einem Standardwert von 0 definiert.Dateibereichsvariablen werden implizit mit einem Standardwert von 0 oder NULL definiert, wenn Sie ihnen keinen expliziten Wert zuweisen - im Gegensatz zu Blockbereichsvariablen, die Sie oben in einer Funktion deklarieren. Das Schlüsselwort extern vermeidet diese implizite Definition und hilft so, Fehler zu vermeiden.
Für Funktionen in Funktionsdeklarationen ist das Schlüsselwort tatsächlich redundant. Funktionsdeklarationen haben keine implizite Definition.
quelle
int i = 2
Wollten Sie die Zeile im 3. Absatz entfernen ? Und ist es richtig zu sagenint i;
, dass der Compiler Speicher für diese Variable zuweist, aber dassextern int i;
der Compiler NICHT Speicher zuweist, sondern woanders nach der Variablen sucht?Das
extern
Schlüsselwort nimmt je nach Umgebung unterschiedliche Formen an. Wenn eine Deklaration verfügbar ist, nimmt dasextern
Schlüsselwort die Verknüpfung wie zuvor in der Übersetzungseinheit angegeben an. Wenn keine solche Erklärungextern
vorliegt, wird eine externe Verknüpfung angegeben.Hier sind die relevanten Absätze aus dem C99-Entwurf (n1256):
quelle
Inline-Funktionen haben spezielle Regeln, was
extern
bedeutet. (Beachten Sie, dass Inline-Funktionen eine C99- oder GNU-Erweiterung sind; sie waren nicht im Original C.Für Nicht-Inline-Funktionen
extern
wird dies nicht benötigt, da es standardmäßig aktiviert ist.Beachten Sie, dass die Regeln für C ++ unterschiedlich sind. Wird beispielsweise
extern "C"
für die C ++ - Deklaration von C-Funktionen benötigt, die Sie von C ++ aus aufrufen möchten, und es gibt unterschiedliche Regeln fürinline
.quelle
Deshalb 10 Jahre später:
extern
in Funktionsdeklaration zur Entfernung;git/git
folgt dieser Schlussfolgerung und wirdextern
aus ihrem Code entfernt (für Git 2.22, Q2 2019).Siehe Commit ad6dad0 , Commit b199d71 , Commit 5545442 (29. April 2019) von Denton Liu (
Denton-L
) .(Zusammengeführt von Junio C Hamano -
gitster
- in Commit 4aeeef3 , 13. Mai 2019)Dies ist jedoch nicht immer einfach:
Siehe Commit 7027f50 (04. September 2019) von Denton Liu (
Denton-L
) .(Zusammengeführt von Denton Liu -
Denton-L
- in Commit 7027f50 , 05. September 2019)Beachten Sie, dass mit Git 2.24 (Q4 2019) alle falschen Daten
extern
gelöscht werden.Siehe Commit 65904b8 (30. September 2019) von Emily Shaffer (
nasamuffin
) .Mit freundlicher Unterstützung von Jeff King (
peff
) .Siehe Commit 8464f94 (21. September 2019) von Denton Liu (
Denton-L
) .Mit freundlicher Unterstützung von Jeff King (
peff
) .(Zusammengeführt von Junio C Hamano -
gitster
- in Commit 59b19bc , 07. Oktober 2019)quelle
Das
extern
Schlüsselwort informiert den Compiler darüber, dass die Funktion oder Variable über eine externe Verknüpfung verfügt - mit anderen Worten, dass sie aus anderen Dateien als der, in der sie definiert ist, sichtbar ist. In diesem Sinne hat es die entgegengesetzte Bedeutung zumstatic
Schlüsselwort. Es ist ein bisschen komisch zu sagenextern
zum Zeitpunkt der Definition zu setzen, da keine anderen Dateien die Definition sichtbar machen würden (oder dies würde zu mehreren Definitionen führen). Normalerweise geben Sieextern
irgendwann eine Deklaration mit externer Sichtbarkeit ein (z. B. eine Header-Datei) und platzieren die Definition an einer anderen Stelle.quelle
Das Deklarieren einer Funktion extern bedeutet, dass ihre Definition zum Zeitpunkt der Verknüpfung und nicht während der Kompilierung aufgelöst wird.
Im Gegensatz zu regulären Funktionen, die nicht als extern deklariert sind, kann sie in jeder der Quelldateien definiert werden (jedoch nicht in mehreren Quelldateien, da sonst ein Linkerfehler angezeigt wird, der besagt, dass Sie mehrere Definitionen der Funktion angegeben haben), einschließlich der in Dies wird als extern deklariert. In diesem Fall löst der Linker die Funktionsdefinition in derselben Datei auf.
Ich denke nicht, dass dies sehr nützlich wäre, aber solche Experimente geben einen besseren Einblick in die Funktionsweise des Compilers und Linkers der Sprache.
quelle
Der Grund dafür ist, dass der Linker zum Zeitpunkt der Verknüpfung versucht, die externe Definition aufzulösen (in Ihrem Fall
extern int f()
). Es spielt keine Rolle, ob es in derselben oder einer anderen Datei gefunden wird, solange es gefunden wird.Hoffe das beantwortet deine Frage.
quelle
extern
dann überhaupt eine Funktion hinzufügen ?