Ich habe die C ++ - FAQs gelesen und einen Satz bemerkt.
main () kann nicht inline sein.
Warum ist das?
Ich habe die C ++ - FAQs gelesen und einen Satz bemerkt.
main () kann nicht inline sein.
Warum ist das?
main
Funktion darin kompiliert wird. Die Antwort lautet also, weil Sie Ihr Betriebssystem nicht neu kompilieren können.
inline
(was nur ein Hinweis ist!).
Antworten:
In C ++ ist es nicht legal, die Hauptfunktion in Ihrem Code aufzurufen, daher kann sie niemals eingebunden werden.
*static_cast<int*>(0) = 10
Kompiliert auch, und das bedeutet nicht, dass es korrekt ist ... wie es bei jeder ODR-Verletzung und so vielen anderen Dingen der Fall ist ... die Tatsache, dass es kompiliert, bedeutet nicht, dass es ein legales Programm ist.
Weil der Standard dies sagt:
[2003: 3.6.1/3]
: Die Funktion main darf nicht innerhalb eines Programms verwendet werden (3.2). Die Verknüpfung (3.5) von main ist implementierungsdefiniert. Ein Programm, das main als inline oder statisch deklariert, ist fehlerhaft. Der Name main ist nicht anderweitig reserviert. [Beispiel: Elementfunktionen, Klassen und Aufzählungen können als main bezeichnet werden, ebenso wie Entitäten in anderen Namespaces. ]]
Und warum steht es so? Weil es versucht, so viel wie möglich über die Implementierung main
dem Einzelnen zu überlassen ... nun, Implementierung ... und die Implementierungen nicht einschränken möchte, indem es verlangt, dass inline
dies hier gültig ist, wenn es wohl keinen praktischen Nutzen hat.
Mein Freund im Ausschuss bestätigte dies:
Es gibt keinen Grund, warum ein
inline
main()
per se nicht funktionieren würde. [..] Ich könnte einen C ++ - Interpreter haben, der Inline aufrufen kannmain()
. [..] [Aber]inline
/static
main()
sind verboten, um hoffentlich Verwirrung zu vermeiden. Es fällt mir schwer, mir vorzustellen, dass die Begründung etwas Zusätzliches zu dem ist, was bereits in [diesen Fragen und Antworten] gesagt wurde.
Übrigens, verwechseln Sie das inline
Hinweis-Schlüsselwort nicht mit tatsächlichen Inlining-Funktionen. Sie können eine Funktion markieren inline
und sie ist möglicherweise nicht physisch inline.
Selbst wenn es wahr wäre, dass main
"nicht inliniert werden kann" (und genau genommen ist es nicht wahr, obwohl Inlining main
ziemlich umständlich und sinnlos wäre, wie in anderen Antworten erläutert), könnte es theoretisch das inline
Hinweis-Schlüsselwort gut unterstützen.
Aus dem oben genannten Grund und in der Antwort von litb: Es würde die Sache ohne wirklichen Nutzen komplizieren.
inline
für main
ist trivial, da sie einfach ignoriert werden kann, was keine Implementierung einschränkt, weshalb dieser mögliche Grund für das Verbot des Standards kein Wasser enthält. Es tut uns leid. Aber ich habe nicht mehr zu bieten als in meiner Antwort, dass es keinen Sinn macht inline
(und darüber sind wir uns einig, denke ich).
main
in mehreren TUs definieren können, ob die Definitionen (unter anderem) alle lexikalisch identisch sind, was nur so wenig Sinn macht, dass es sich lohnt, es zu verbieten.
main
hat dies eine Bedeutung, die mit der Laufzeit der Implementierung und mit dem Host-Betriebssystem interagieren muss (da dies der Programmeinstiegspunkt ist). Daher ist es für ein Komitee von Personen nicht sinnvoll, zu viel darüber zu schreiben. Daran erinnert , dass die Verknüpfung von anderen Funktionen benutzerdefiniert ist so in der Tat, der Standard ist beschränke main
leicht hier, mit den Worten „zu Ihrem Compiler Anbieter zu hören , weil sie dies wählen bekommen Sie nicht“. :)
Die C-Laufzeitbibliothek muss dieses Symbol finden, um zu "wissen", welche Funktion ausgeführt werden soll.
call
auf die main()
Funktion, und es fast immer dynamisch verbunden ist. In einem typischen Fall kann es also auf keinen Fall funktionieren .
Sie können main () nicht direkt aufrufen (dies ist in c ++ verboten), daher macht es keinen Sinn, es einzubinden.
Wird normalerweise main()
von der init()
Systemfunktion aufgerufen . Daher ist es erforderlich, dass es genau eine Definition für geben kann main()
.
Wenn wir nun inline
die main()
Funktion können und in eine Header-Datei aufnehmen können, gibt es für jede Übersetzungseinheit eine andere Definition für main()
. Welches ist nicht erlaubt. Sie können main()
in a namespace
und inline
es deklarieren . Aber nicht das Globale main()
.
inline
.
static int main()
es schlecht geformt ist: D)
static int main()
ist äquivalent zu namespace { int main() }
. Was ich in der Antwort behandelt habe.
main
Funktion identifizieren. Worum geht es also?
Zunächst müssen Sie verstehen, wie die Arbeit mit Inline funktioniert
Beispiel:
inline void f() {
int a = 3;
a += 3;
cout << a;
}
int main() {
f();
return 0;
}
wird für den Compiler wie folgt aussehen:
int main() {
int a = 3;
a += 3;
cout << a;
return 0;
}
Wie möchten Sie in diesem Beispiel die Hauptinline erstellen? Diese Methode ist sofort inline.
inline
d-Funktion mit nur einem Aufruf und der main
Funktion mit nur einem Aufruf?
This method is inline immediately.
Nicht wahr. inline
ist nur ein Hinweis . Es führt kein Inlining von Funktionen durch.
Der C ++ - Standard besagt, dass die main
Funktion gemäß der Antwort von @Tomalak Geret'kal nicht eingebunden werden kann. Diese Antwort diskutiert die Möglichkeit des Inlining der main
Funktion, wenn die Einschränkung im Standard aufgehoben wurde.
Definition von Inline
Das inline
Schlüsselwort ist ein Vorschlag an den Compiler, den Inhalt der Funktion vor Ort einzufügen. Eine Absicht besteht darin, den Overhead zu beseitigen, der beim Aufrufen und Zurückkehren von einer Funktion (Unterroutine) vorhanden ist.
Eine wichtige Situation beim Inlining ist der Fall, in dem ein Zeiger auf die Funktion vorhanden ist. In diesem Fall muss mindestens eine statische Kopie der Funktion vorhanden sein. In diesem Fall kann der Linker "externe Verknüpfungen" der Inline-Funktion auflösen, da es eine statische Version gibt.
Es ist wichtig zu beachten, dass der Compiler und der Linker bestimmen, ob der Inhalt eingefügt oder eine einzelne Instanz der Funktion aufgerufen werden soll.
Bemerkenswert sind auch Funktionen, die vom Programmierer nicht markiert werden auch vom Compiler eingebunden werden können.
Die Hauptfunktion inlining
Da es nur ein Aufruf ist main
erlaubt, wie es verbunden ist , ist an den Compiler auf. Einzelne Instanzen von Inline-Funktionen sind im Standard zulässig. Der Compiler darf eine inlined
Funktion in einen Funktionsaufruf in eine einzelne Instanz konvertieren . Der Compiler würde also einen Inline-Vorschlag für die Funktion ignorierenmain
.
Der Compiler und der Linker müssten sicherstellen, dass nur eine Instanz der Inline- main
Funktion vorhanden ist. Hier kommt der schwierige Teil ins Spiel, insbesondere bei der externen Verknüpfung. Ein Prozess, um sicherzustellen, dass eine Instanz vorhanden ist, besteht darin, Informationen zu hinterlassen, dass eine Übersetzung eine Hauptfunktion hat, unabhängig davon, ob sie inline ist oder nicht. Hinweis: Wenn eine Inline-Funktion aufgerufen wird, kann der Compiler die Funktion aus den Symboltabellen für die externe Verknüpfung entfernen, da die Funktion nicht von externen Funktionen aufgerufen wird.
Zusammenfassung
Technisch gesehen hindert nichts die main
Inline-Funktion der Funktion. Die Maschinerie existiert bereits zum Konvertieren von Inline-Funktionen in einzelne Instanzen und zum Identifizieren mehrerer Instanzen einer Funktion. Wenn es einen Zeiger auf eine inline-Funktion gibt, wird eine einzelne Instanz einer Funktion erstellt, sodass sie eine Adresse hat. Diese Maschinerie würde die Anforderungen der Laufzeitbibliothek erfüllen, um main
eine Adresse zu haben. Im Fall von inline
für die main
Funktion würde sie ignoriert, aber es sollte keinen Grund geben, diese Syntax zu verhindern (außer verwirrende Personen). Schließlich gibt es bereits redundante Syntaxfälle, z. B. das Deklarieren eines Parameters, der als Wert (Kopie) als übergeben wird const
.
"Das ist nur meine Meinung, ich könnte mich irren." - Dennis Miller, Komiker.
Andere haben bemerkt, dass eine Anrufung von main
auf der Ebene des Maschinencodes nicht sinnvoll eingefügt werden kann. Das ist Müll. Es würde ein bisschen Hilfe vom Linker erfordern (wie die globale Optimierung) oder eine Neukompilierung eines Teils der Laufzeitbibliothek pro Anwendung, aber es ist durchaus machbar, hier kein technisches Problem.
Doch das Hinting des Effekt inline
, dass Anrufe vorzugsweise inlined werden sollen, ist irrelevant für eine Funktion , die nur einmal und auf der obersten Ebene der Kontrolle genannt wird, alsmain
ist.
Die einzige garantierte Wirkung voninline
ist eine externe Verknüpfung Funktion zu ermöglichen , definiert werden (identisch) in zwei oder mehr Übersetzungseinheiten, dh Auswirkungen auf die One Definition Rule.
In der Praxis ermöglicht dies das Platzieren der Definition in einer Header-Datei, und das Platzieren in einer Header-Datei ist auch praktisch erforderlich, um identische Definitionen zu gewährleisten.
Das macht Sinn nicht main
, so gibt es keinen Grund für main
sein inline
.
main
zu sein inline
" ist zwingend, aber keine direkte Erklärung dafür, warum es so gemacht wurde, dass es nicht markiert werden kann inline
.
main
nicht perfekt. Zum Beispiel habe ich immer gedacht und denke immer noch, dass das Bit "nach der ersten Aussage von main" grundlegend falsch ist. Aber ich habe noch nie darüber gesprochen. Vielleicht ist es nur mein unvollkommenes Verständnis von Englisch ...
Sie können nur main
einmal definieren . Putten inline
würde also keinen Zweck erfüllen - hat inline
nur einen wesentlichen Zweck für Funktionen, die Sie mehrmals in einem Programm definieren können (alle Definitionen werden so behandelt, als ob es nur eine Definition gäbe und alle Definitionen müssen gleich sein).
Da inline
Funktionen in einem Programm mehrfach definiert werden können und inline
auch dazu dienen, eine inline
markierte Funktion so schnell wie möglich aufzurufen, verlangt der Standard, dass inline
Funktionen in jeder Übersetzungseinheit definiert werden, in der sie verwendet wird. Daher werfen Compiler normalerweise die Definition einer Funktion weg, wenn dies der Fall ist inline
und die Funktion vom Code in der aktuellen Übersetzungseinheit nicht verwendet wurde. Das zu tun main
wäre völlig falsch, was zeigt, dass inline
und die Semantik main
völlig inkompatibel ist.
Beachten Sie, dass die Frage in Ihrem Titel "Warum kann main () in C ++ nicht eingefügt werden?" und die Aussage, die Sie aus dem Standard zitieren, betrifft verschiedene Dinge. Sie fragen, ob die Funktion inline sein kann, was üblicherweise so verstanden wird, dass der Code einer aufgerufenen Funktion ganz oder teilweise in die aufrufende Funktion eingefügt wird. Nur eine Funktion zu markieren inline
bedeutet nicht, diese Funktion überhaupt zu inlinieren. Es ist ganz und gar die Entscheidung des Compilers, und wenn Sie nie aufrufen main
(und dies auch nicht können), gibt es natürlich nichts zu tun.
main
Inline erfordern würde , es sein. In der Vergangenheit brauchte C ++ keine Magie. (Aber das war vor Vorlagen.)
Wenn Sie statisch mit der CRT verknüpft sind und ein Inlining zur Kompilierung der Verknüpfungszeit aktiviert haben (wie dies bei MSVC der Fall ist), ist es möglicherweise möglich, diese zu integrieren.
Aber es macht nicht wirklich Sinn. Es wird aufgerufen , sobald und dass Funktionsaufruf-Overhead praktisch Null auf alles verglichen wird sonst noch vor der ersten Zeile in Haupt ausführt erfolgt.
...
Aaand, es ist eine einfache Möglichkeit, das Symbol nur einmal in Ihrer ausführbaren Datei erscheinen zu lassen. :) :)
Es gibt eine Reihe grundlegender Gründe. Grundsätzlich main
wird von der Basisinitialisierungsroutine der Laufzeit aufgerufen und nur von dort. Dieser Code wurde (offensichtlich) kompiliert, ohne zu wissen, dass Ihr Code main
inline war. Moderne Compilertechnologie ist in der Lage, Modulgrenzen zu überschreiten, ist jedoch eine erweiterte Funktion, die von vielen älteren Compilern nicht unterstützt wird. Und natürlich sind die Vorteile von Inlining nur dann vorhanden, wenn eine Funktion sehr häufig aufgerufen wird. per definitionem main
wird genau einmal aufgerufen, nicht mehr und nicht weniger.
Ich sehe, dass der Standard dies sagt, aber die wirkliche praktische Antwort wäre so einfach wie die Aussage, dass die jedem C- und C ++ - Programm hinzugefügte Laufzeit irgendwann in der ausführbaren Datei aufgerufen werden muss. Diese Funktion sollte ein externes Symbol (und eine Adresse beim Ausführen) haben, damit der Linker feststellen kann, dass sie zu Beginn der Ausführung aufgerufen wird. Daher können Sie es nicht als deklarieren inline
, da der Compiler inline kein externes Symbol dafür generieren würde.
inline
führt nicht unbedingt dazu, dass die Funktion inline wird.
inline
Funktion verfügt über eine externe Verknüpfung, es sei denn, es handelt sich um eine explizit deklarierte Namespace-Bereichsfunktion static
.
Für die meisten Kombinationen von Compiler / Archetecture ist die main()
Funktion in der Quelle zu einer einigermaßen normalen Funktion in der endgültigen Binärdatei. Dies liegt nur daran, dass es für diese Archetekturen praktisch ist, nicht daran, dass der Standard dies vorschreibt.
Bei speicherbeschränkten Archetectures optimieren viele Compiler, die anstelle eines dynamischen Linker-freundlichen Containers (wie elf oder xcoff) eine flache Binärdatei (wie das Intex-Hex-Format) erzeugen, die gesamte Boilerplate, da sie nur aufgebläht wäre. Einige Architekturen unterstützen Funktionsaufrufe überhaupt nicht (auf diesen Plattformen ist nur eine begrenzte Teilmenge von C ++ möglich.)
Um die unterschiedlichsten Architekturen und Build-Umgebungen zu unterstützen, behalten die Standardwahlen die Semantik von bei main()
so offen wie möglich, damit der Compiler das tun kann, was für die unterschiedlichsten Plattformen richtig ist. Das bedeutet, dass viele in der gesamten Sprache verfügbare Funktionen nicht auf das Starten und Herunterfahren der Anwendung selbst angewendet werden können.
Wenn Sie so etwas wie eine Inline-Funktion main()
(oder einen Wiedereintritt oder eine ausgefallene Funktion) benötigen, können Sie die Hauptfunktion natürlich etwas anderes nennen:
inline int myMain(int argc, char **argv) { /* whatever */ }
int main(int argc, char **argv) { return myMain(argc, argv); }
Inline-Funktionen haben standardmäßig einen statischen Gültigkeitsbereich. Wenn wir main () als Inline deklarieren, ist der Gültigkeitsbereich auf die Datei beschränkt, in der er definiert ist. Die C-Startbibliothek (vom Compilerhersteller bereitgestellt) benötigt jedoch 'main' als globales Symbol. Es gibt einige Compiler, mit denen die Einstiegspunktfunktion (z. B. main) mithilfe von Linker-Flags geändert werden kann.
Inline-Funktionen haben normalerweise keine Adresse, daher gibt es keine tragbare Möglichkeit, main aufzurufen. main () benötigt eine Adresse, in die der Init-Code springen kann. Inline-Funktionen sollen in der aufrufenden Funktion stecken bleiben. Wenn main inline ist, sollte es in den Init-Code des Programms eingebunden werden, der ebenfalls nicht portierbar ist.
inline
.
Betriebssystem lädt Binärdaten in den Speicher; sucht nach Einstiegspunkt (das 'Hauptsymbol' in c / c ++); macht einen weiten Sprung zu den Adressen des Einstiegspunkt-Labels. Das Betriebssystem weiß nichts über die Hauptfunktion in Ihrem Code, bis das Programm nicht geladen ist.
main
. Stattdessen ruft das Betriebssystem den Einstiegspunkt auf Maschinencodeebene für das Programm auf. Für C und C ++ ist dieser Einstiegspunkt normalerweise eine Funktion in der Laufzeitbibliothek, die wiederum verschiedene Initialisierungsaufgaben ausführt, dann aufruft main
und schließlich bereinigt (z. B. installierte Exit-Handler aufruft) und beendet.