Ich frage, weil mein Compiler das zu glauben scheint, obwohl ich es nicht tue.
echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall
Clang gibt dabei keine Warnung oder Fehler aus, und gcc gibt nur die sanfte Warnung aus 'main' is usually a function [-Wmain]
:, aber nur, wenn es als C kompiliert wurde. Die Angabe von a -std=
scheint keine Rolle zu spielen.
Andernfalls wird es gut kompiliert und verknüpft. Aber bei der Ausführung endet es sofort mit SIGBUS
(für mich).
Lesen Sie die (ausgezeichneten) Antworten unter Was sollte main () in C und C ++ zurückgeben? und eine schnelle grep durch die Sprachdaten, wäre es sicher scheint mir , dass eine Hauptfunktion erforderlich ist. Aber die Aussprache von gcc's -Wmain
('main' ist normalerweise eine Funktion) (und der Mangel an Fehlern hier) scheint möglicherweise etwas anderes zu suggerieren.
Aber wieso? Gibt es dafür einen seltsamen Randfall oder eine „historische“ Verwendung? Weiß jemand was gibt?
Mein Punkt ist wohl, dass ich wirklich denke, dass dies ein Fehler in einer gehosteten Umgebung sein sollte, oder?
gcc -std=c99 -pedantic ...
-pedantic
oder keine-std
. Mein Systemc99
kompiliert dies auch ohne Warnung oder Fehler ...main
, die wahrscheinlich nicht funktioniert. Wenn Sie main mit dem "richtigen" Wert initialisieren, wird es möglicherweise tatsächlich zurückgegeben ...main
)main=195;
Antworten:
Da die Frage doppelt als C und C ++ gekennzeichnet ist, wäre die Begründung für C ++ und C unterschiedlich:
xyz
und einer freistehenden globalen Funktionxyz(int)
. Der Namemain
wird jedoch nie entstellt.Das ist es, was hier vor sich geht: Der Linker erwartet, ein Symbol zu finden
main
, und das tut er auch. Es "verdrahtet" dieses Symbol, als wäre es eine Funktion, weil es es nicht besser weiß. Der Teil der Laufzeitbibliothek, der die Steuerung an denmain
Linker abfragtmain
, der Linker gibt ihm ein Symbolmain
, damit die Linkphase abgeschlossen werden kann. Dies schlägt natürlich zur Laufzeit fehl, da diesmain
keine Funktion ist.Hier ist ein weiteres Beispiel für dasselbe Problem:
Datei xc:
Datei yc:
Kompilieren:
Dies wird kompiliert und wahrscheinlich ausgeführt, aber es ist ein undefiniertes Verhalten, da sich der Typ des dem Compiler versprochenen Symbols von dem tatsächlichen Symbol unterscheidet, das dem Linker bereitgestellt wird.
Was die Warnung betrifft, halte ich es für vernünftig: Mit C können Sie Bibliotheken erstellen, die keine
main
Funktion haben, sodass der Compiler den Namenmain
für andere Zwecke freigibt, wenn Siemain
aus einem unbekannten Grund eine Variable definieren müssen .quelle
main
sie unterliegen in C ++ keiner Namensverfälschung (so scheint es), unabhängig davon, ob es sich um eine Funktion handelt oder nicht.main
etwas anderes als eine Funktion zu definieren . Die Antwort bietet eine Erklärung für beide Teile.main
ist kein reserviertes Wort , es ist nur eine vordefinierte Kennung (wiecin
,endl
,npos
...), so dass Sie rief eine Variable deklarieren könntemain
, es zu initialisieren und dann seinen Wert auszudrucken.Natürlich:
main()
Funktion (Bibliotheken) haben.BEARBEITEN
Einige Referenzen:
main
ist kein reserviertes Wort (C ++ 11):C ++ 11 - [basic.start.main] 3.6.1.3
Reservierte Wörter in Programmiersprachen .
Reservierte Wörter werden vom Programmierer möglicherweise nicht neu definiert, aber vordefinierte Wörter können häufig in gewisser Weise überschrieben werden. Dies ist der Fall bei
main
: Es gibt Bereiche, in denen eine Deklaration, die diesen Bezeichner verwendet, ihre Bedeutung neu definiert.quelle
main()
Funktion, aber Sie können sie nicht als Programm verknüpfen. Was hier passiert ist, dass ein "gültiges" Programm ohne einmain()
, nur ein verknüpft wirdmain
.cin
undendl
sind nicht im Standard-Namespace - sie sind imstd
Namespace.npos
ist Mitglied vonstd::basic_string
.main
ist als globaler Name reserviert. Keines der anderen Dinge, die Sie erwähnt habenmain
, ist vordefiniert.main
darf. C ++ sagt "Eine Implementierung darf die Hauptfunktion nicht vordefinieren" und C sagt "Die Implementierung deklariert keinen Prototyp für diese Funktion."Ist
int main;
ein gültiges C / C ++ - Programm?Es ist nicht ganz klar, was ein C / C ++ - Programm ist.
Ist
int main;
ein gültiges C-Programm?Ja. Eine freistehende Implementierung darf ein solches Programm akzeptieren.
main
muss in einer freistehenden Umgebung keine besondere Bedeutung haben.Es ist in einer gehosteten Umgebung nicht gültig.
Ist
int main;
ein gültiges C ++ - Programm?Das Gleiche gilt.
Warum stürzt es ab?
Das Programm muss in Ihrer Umgebung keinen Sinn ergeben . In einer freistehenden Umgebung sind der Start und die Beendigung des Programms sowie die Bedeutung von
main
implementierungsdefiniert.Warum warnt mich der Compiler?
Der Compiler kann Sie vor allem warnen, was ihm gefällt, solange er keine konformen Programme ablehnt. Auf der anderen Seite ist nur eine Warnung erforderlich, um ein nicht konformes Programm zu diagnostizieren. Da diese Übersetzungseinheit nicht Teil eines gültigen gehosteten Programms sein kann, ist eine Diagnosemeldung gerechtfertigt.
Ist
gcc
eine freistehende Umgebung oder eine gehostete Umgebung?Ja.
gcc
dokumentiert das-ffreestanding
Kompilierungsflag. Fügen Sie es hinzu, und die Warnung verschwindet. Sie können es verwenden, wenn Sie z. B. Kernel oder Firmware erstellen.g++
dokumentiert solche Flagge nicht. Die Bereitstellung scheint keine Auswirkungen auf dieses Programm zu haben. Es ist wahrscheinlich sicher anzunehmen, dass die von g ++ bereitgestellte Umgebung gehostet wird. Das Fehlen einer Diagnose ist in diesem Fall ein Fehler.quelle
Dies ist eine Warnung, da sie technisch nicht unzulässig ist. Der Startcode verwendet die Symbolposition von "main" und springt mit den drei Standardargumenten (argc, argv und envp) dorthin. Dies ist nicht der Fall und kann zum Zeitpunkt der Verknüpfung nicht überprüfen, ob es sich tatsächlich um eine Funktion handelt oder ob diese Argumente vorhanden sind. Dies ist auch der Grund, warum int main (int argc, char ** argv) funktioniert - der Compiler kennt das envp-Argument nicht und es wird einfach nicht verwendet, und es handelt sich um eine Aufruferbereinigung.
Als Witz könnte man so etwas machen
Auf einem x86-Computer wird es nicht nur kompiliert, sondern funktioniert auch, wenn Warnungen und ähnliches ignoriert werden.
Jemand hat eine ähnliche Technik verwendet, um eine ausführbare Datei (eine Art) zu schreiben, die direkt auf mehreren Architekturen ausgeführt wird - http://phrack.org/issues/57/17.html#article . Es wurde auch verwendet, um die IOCCC zu gewinnen - http://www.ioccc.org/1984/mullender/mullender.c .
quelle
int main __attribute__ ((section (".text")))= 0xC3C3C3C3;
Ist es ein gültiges Programm?
Nein.
Es ist kein Programm, da es keine ausführbaren Teile enthält.
Ist es gültig zu kompilieren?
Ja.
Kann es mit einem gültigen Programm verwendet werden?
Ja.
Nicht jeder kompilierte Code muss ausführbar sein, um gültig zu sein. Beispiele sind statische und dynamische Bibliotheken.
Sie haben effektiv eine Objektdatei erstellt. Es ist keine gültige ausführbare Datei, jedoch kann ein anderes Programm eine Verknüpfung zu dem Objekt
main
in der resultierenden Datei herstellen, indem es zur Laufzeit geladen wird.Sollte dies ein Fehler sein?
Traditionell erlaubt C ++ dem Benutzer, Dinge zu tun, die so aussehen, als hätten sie keine gültige Verwendung, aber die zur Syntax der Sprache passen.
Ich meine, das könnte sicher als Fehler eingestuft werden, aber warum? Welchen Zweck würde das erfüllen, den die Warnung nicht erfüllt?
Solange theoretisch die Möglichkeit besteht, dass diese Funktionalität im eigentlichen Code verwendet wird, ist es sehr unwahrscheinlich, dass ein aufgerufenes
main
Nichtfunktionsobjekt zu einem sprachlichen Fehler führt.quelle
main
. Wie kann ein gültiges Programm, für das eine extern sichtbare Funktion benannt sein mussmain
, darauf verlinken?main
Funktion definiert .int main;
Definition zur Programmverknüpfungszeit nicht sichtbar ist.Ich möchte die bereits gegebenen Antworten unter Berufung auf die tatsächlichen Sprachstandards ergänzen.
Ist 'int main;' ein gültiges C-Programm?
Kurze Antwort (meiner Meinung nach): Nur wenn Ihre Implementierung eine "freistehende Ausführungsumgebung" verwendet.
Alle folgenden Zitate aus C11
5. Umwelt
5.1.2 Ausführungsumgebungen
5.1.2.1 Freistehende Umgebung
5.1.2.2 Gehostete Umgebung
5.1.2.2.1 Programmstart
Von diesen wird folgendes beobachtet:
In einer freistehenden Ausführungsumgebung würde ich argumentieren, dass es sich um ein gültiges Programm handelt, das keinen Start zulässt, da dafür keine Funktion vorhanden ist, wie in 5.1.2 erforderlich. In einer gehosteten Ausführungsumgebung kann Ihr Code zwar ein Objekt mit dem Namen main einführen , aber keinen Rückgabewert bereitstellen. Daher würde ich argumentieren, dass es in diesem Sinne kein gültiges Programm ist, obwohl man auch vorher argumentieren könnte, wenn das Programm dies nicht ist soll ausgeführt werden (on möchte möglicherweise nur Daten bereitstellen), dann erlaubt es einfach nicht, genau das zu tun.
Ist 'int main;' ein gültiges C ++ - Programm?
Kurze Antwort (meiner Meinung nach): Nur wenn Ihre Implementierung eine "freistehende Ausführungsumgebung" verwendet.
Zitat aus C ++ 14
3.6.1 Hauptfunktion
Im Gegensatz zum C11-Standard gelten hier weniger Einschränkungen für die freistehende Ausführungsumgebung, da überhaupt keine Startfunktion erwähnt wird, während für eine gehostete Ausführungsumgebung der Fall so ziemlich der gleiche ist wie für C11.
Wieder würde ich argumentieren, dass Ihr Code für den gehosteten Fall kein gültiges C ++ 14-Programm ist, aber ich bin sicher, dass es für den freistehenden Fall ist.
Da meine Antwort nur die Ausführungsumgebung berücksichtigt , denke ich, dass die Antwort von dasblinkenlicht ins Spiel kommt, da die Namensverfälschung in der Übersetzungsumgebung vorher erfolgt. Hier bin ich mir nicht so sicher, ob die obigen Zitate so streng eingehalten werden.
quelle
Der Fehler liegt bei Ihnen. Sie hat nicht angegeben was eine Funktion mit dem Namen ,
main
dass die Renditen einint
und versucht , das Programm in einer gehosteten Umgebung zu verwenden.Angenommen, Sie haben eine Kompilierungseinheit, die eine globale Variable mit dem Namen definiert
main
. Dies kann in einer freistehenden Umgebung durchaus legal sein, da das, was ein Programm ausmacht, der Implementierung in freistehenden Umgebungen überlassen bleibt.Angenommen, Sie haben eine andere Kompilierungseinheit, die eine globale Funktion mit dem Namen definiert, die eine
main
zurückgibtint
und keine Argumente akzeptiert. Genau das benötigt ein Programm in einer gehosteten Umgebung.Alles ist in Ordnung, wenn Sie nur die erste Kompilierungseinheit in einer freistehenden Umgebung und die zweite nur in einer gehosteten Umgebung verwenden. Was ist, wenn Sie beide in einem Programm verwenden? In C ++ haben Sie die One-Definition-Regel verletzt. Das ist undefiniertes Verhalten. In C haben Sie gegen die Regel verstoßen, die vorschreibt, dass alle Verweise auf ein einzelnes Symbol konsistent sein müssen. Wenn nicht, ist es undefiniertes Verhalten. Undefiniertes Verhalten ist ein "Raus aus dem Gefängnis, frei!" Karte an Entwickler einer Implementierung. Alles, was eine Implementierung als Reaktion auf undefiniertes Verhalten tut, entspricht dem Standard. Die Implementierung muss nicht vor undefiniertem Verhalten warnen oder gar erkennen.
Was ist, wenn Sie nur eine dieser Kompilierungseinheiten verwenden, aber die falsche (was Sie getan haben)? In C ist die Situation eindeutig. Wenn die Funktion
main
in einer der beiden Standardformen in einer gehosteten Umgebung nicht definiert wird, ist dies ein undefiniertes Verhalten. Angenommen, Sie haben überhaupt nicht definiertmain
. Der Compiler / Linker muss nichts zu diesem Fehler sagen. Dass sie sich beschweren, ist eine nette Sache in ihrem Namen. Dass das C-Programm fehlerfrei kompiliert und verknüpft wurde, ist Ihre Schuld, nicht die des Compilers.In C ++ ist dies etwas weniger klar, da das Versagen beim Definieren der Funktion
main
in einer gehosteten Umgebung eher ein Fehler als ein undefiniertes Verhalten ist (mit anderen Worten, es muss diagnostiziert werden). Die einzige Definitionsregel in C ++ bedeutet jedoch, dass Linker ziemlich dumm sein können. Die Aufgabe des Linkers besteht darin, externe Referenzen aufzulösen, und dank der One-Definition-Regel muss der Linker nicht wissen, was diese Symbole bedeuten. Sie haben ein Symbol mit dem Namen angegebenmain
. Der Linker erwartet ein Symbol mit dem Namen . Für den Linker istmain
also alles in Ordnung.quelle
Für C ist es bisher ein implementierungsdefiniertes Verhalten.
Wie die ISO / IEC9899 sagt:
quelle
Nein, dies ist kein gültiges Programm.
Für C ++ wurde dies kürzlich durch den Fehlerbericht 1886: Sprachverknüpfung für main (), der besagt:
und ein Teil der Entschließung enthielt die folgende Änderung:
Wir finden diesen Wortlaut im neuesten C ++ - Entwurfsstandard N4527 , dem C ++ 1z-Entwurf.
Die neuesten Versionen von clang und gcc machen dies jetzt zu einem Fehler ( sehen Sie es live ):
Vor diesem Fehlerbericht war es ein undefiniertes Verhalten, für das keine Diagnose erforderlich ist. Auf der anderen Seite erfordert schlecht geformter Code eine Diagnose. Der Compiler kann dies entweder als Warnung oder als Fehler ausgeben.
quelle
main()
.) Ich verstehe die Gründe dafür,main()
dass eine explizite Verknüpfungsspezifikation nicht zulässig ist , aber ich verstehe nicht , dassmain()
eine C ++ - Verknüpfung erforderlich ist . Natürlich funktioniert der Standard nicht direkt Adresse wie ABI Verknüpfung / namen Mangeln zu handhaben , aber in der Praxis ( zum Beispiel mit Itanium ABI) würde dies manglemain()
an_Z4mainv
. Was vermisse ich?