Wenn ich versuche, diesen Code zu erstellen
inline void f() {}
int main()
{
f();
}
über die Kommandozeile
gcc -std=c99 -o a a.c
Ich erhalte einen Linkerfehler (undefinierter Verweis auf f
). Der Fehler verschwindet, wenn ich static inline
oder extern inline
statt nur verwende inline
oder wenn ich mit kompiliere -O
(die Funktion ist also tatsächlich inline).
Dieses Verhalten scheint in Absatz 6.7.4 (6) des C99-Standards definiert zu sein:
Wenn alle Dateibereichsdeklarationen für eine Funktion in einer Übersetzungseinheit den
inline
Funktionsspezifizierer ohne enthaltenextern
, ist die Definition in dieser Übersetzungseinheit eine Inline-Definition. Eine Inline-Definition bietet keine externe Definition für die Funktion und verbietet keine externe Definition in einer anderen Übersetzungseinheit. Eine Inline-Definition bietet eine Alternative zu einer externen Definition, mit der ein Übersetzer jeden Aufruf der Funktion in derselben Übersetzungseinheit implementieren kann. Es ist nicht angegeben, ob ein Aufruf der Funktion die Inline-Definition oder die externe Definition verwendet.
Wenn ich das alles richtig verstehe, kompiliert eine Kompilierungseinheit mit einer inline
wie im obigen Beispiel definierten Funktion nur dann konsistent, wenn es auch eine externe Funktion mit demselben Namen gibt, und ich weiß nie, ob meine eigene Funktion oder die externe Funktion aufgerufen wird.
Ist dieses Verhalten nicht völlig dumm? Ist es jemals sinnvoll, eine Funktion inline
ohne static
oder extern
in C99 zu definieren ? Vermisse ich etwas
Zusammenfassung der Antworten
Natürlich hat mir etwas gefehlt und das Verhalten ist nicht dumm. :) :)
Wie Nemo erklärt , besteht die Idee darin, die Definition der Funktion festzulegen
inline void f() {}
in der Header-Datei und nur eine Deklaration
extern inline void f();
in der entsprechenden .c-Datei. Nur die extern
Deklaration löst die Erzeugung von extern sichtbarem Binärcode aus. Und es gibt in der Tat keine Verwendung inline
in einer .c-Datei - es ist nur in Headern nützlich.
Wie die in Jonathans Antwort zitierte Begründung des C99-Komitees erläutert, inline
dreht sich alles um Compiler-Optimierungen, bei denen die Definition einer Funktion am Ort eines Aufrufs sichtbar sein muss. Dies kann nur erreicht werden, indem die Definition in den Header eingefügt wird, und natürlich darf eine Definition in einem Header nicht jedes Mal Code ausgeben, wenn sie vom Compiler gesehen wird. Da der Compiler jedoch nicht gezwungen ist, eine Funktion tatsächlich zu inline, muss irgendwo eine externe Definition vorhanden sein.
inline
ohnestatic
undextern
gibt. Leider wird keines dieser Probleme in dieser Frage behandelt.Antworten:
Eigentlich beantwortet diese hervorragende Antwort auch Ihre Frage, denke ich:
Was macht extern inline?
Die Idee ist, dass "inline" in einer Header-Datei und dann "extern inline" in einer .c-Datei verwendet werden kann. Mit "extern inline" weisen Sie den Compiler an, welche Objektdatei den (extern sichtbaren) generierten Code enthalten soll.
[aktualisieren, ausarbeiten]
Ich glaube nicht, dass "inline" (ohne "static" oder "extern") in einer .c-Datei verwendet werden kann. In einer Header-Datei ist dies jedoch sinnvoll und erfordert eine entsprechende "externe Inline" -Deklaration in einer .c-Datei, um den eigenständigen Code tatsächlich zu generieren.
quelle
inline void f() {}
in den Header undextern inline void f();
in die .c-Datei schreibe ? Die eigentliche Funktionsdefinition geht also in den Header und die .c-Datei enthält in diesem Fall lediglich eine Deklaration in umgekehrter Reihenfolge?inline
ohnestatic
oderextern
. Natürlichstatic inline
ist das in Ordnung, aber darum geht es in dieser Frage und Antwort nicht.-std=c99
anstelle von verwenden-std=gnu89
.Aus der Norm (ISO / IEC 9899: 1999) selbst:
Das C99-Komitee hat eine Begründung verfasst , in der es heißt:
quelle
> Ich erhalte einen Linkerfehler (undefinierter Verweis auff
)Funktioniert hier: Linux x86-64, GCC 4.1.2. Kann ein Fehler in Ihrem Compiler sein; Ich sehe in dem zitierten Absatz nichts aus dem Standard, der das gegebene Programm verbietet. Beachten Sie die Verwendung von if anstelle von iff .Wenn Sie also das Verhalten der Funktion kennen
f
und sie in einer engen Schleife aufrufen möchten, können Sie ihre Definition kopieren und in ein Modul einfügen, um Funktionsaufrufe zu verhindern. oder Sie können eine Definition angeben, die für die Zwecke des aktuellen Moduls gleichwertig ist (überspringt jedoch die Eingabevalidierung oder eine beliebige Optimierung, die Sie sich vorstellen können). Der Compiler-Writer hat jedoch die Möglichkeit, stattdessen die Programmgröße zu optimieren.quelle