Was ist die richtige Erklärung von main?

147

Was ist die richtige Signatur der mainFunktion in C ++? Was ist der richtige Rückgabetyp und was bedeutet es, einen Wert von zurückzugeben main? Was sind die zulässigen Parametertypen und welche Bedeutung haben sie?

Ist das systemspezifisch? Haben sich diese Regeln im Laufe der Zeit geändert? Was passiert, wenn ich sie verletze?

Fredoverflow
quelle
1
Dies hängt sehr eng mit dem zusammen, was mainin C und C ++ zurückgegeben werden soll , oder ist ein Duplikat davon .
Jonathan Leffler
@JonathanLeffler Kein Scherz ... es wurde vor ungefähr 8 Monaten zur Liste der Duplikate in Revision 6 hinzugefügt .
Fredoverflow

Antworten:

192

Die mainFunktion muss im globalen Namespace als Nichtmitgliedsfunktion deklariert werden. Dies bedeutet, dass es weder eine statische oder nicht statische Elementfunktion einer Klasse sein noch in einem Namespace (auch nicht im unbenannten Namespace) platziert werden kann.

Der Name mainist in C ++ nur als Funktion im globalen Namespace reserviert. Es steht Ihnen frei, andere benannte Entitäten zu deklarieren main, darunter unter anderem Klassen, Variablen, Aufzählungen, Elementfunktionen und Nichtmitgliedsfunktionen, die nicht im globalen Namespace enthalten sind.

Sie können eine Funktion mainals Elementfunktion oder in einem Namespace deklarieren , aber eine solche Funktion ist nicht die mainFunktion, die angibt, wo das Programm startet.

Die mainFunktion kann nicht als staticoder deklariert werden inline. Es kann auch nicht überladen werden; mainIm globalen Namespace kann nur eine Funktion benannt sein .

Die mainFunktion kann in Ihrem Programm nicht verwendet werden: Sie dürfen die mainFunktion weder von einer beliebigen Stelle in Ihrem Code aus aufrufen noch ihre Adresse übernehmen.

Der Rückgabetyp von mainmuss seinint . Es ist kein anderer Rückgabetyp zulässig (diese Regel ist fett gedruckt, da häufig falsche Programme mainmit einem Rückgabetyp von deklariert werden void. Dies ist wahrscheinlich die am häufigsten verletzte Regel in Bezug auf die mainFunktion).

Es gibt zwei Erklärungen main, die erlaubt sein müssen:

int main()               // (1)
int main(int, char*[])   // (2)

In (1) gibt es keine Parameter.

In (2) gibt es zwei Parameter , und sie werden in herkömmlicher Weise benannt argcund argvdargestellt. argvist ein Zeiger auf ein Array von C-Zeichenfolgen, die die Argumente für das Programm darstellen. argcist die Anzahl der Argumente im argvArray.

argv[0]Enthält normalerweise den Namen des Programms, dies ist jedoch nicht immer der Fall. argv[argc]ist garantiert ein Nullzeiger.

Beachten Sie, dass, da ein Array-Typ-Argument (wie char*[]) eigentlich nur ein getarntes Zeigertyp-Argument ist, die folgenden beiden gültige Schreibweisen (2) sind und beide genau dasselbe bedeuten:

int main(int argc, char* argv[])
int main(int argc, char** argv)

Einige Implementierungen erlauben möglicherweise andere Arten und Anzahlen von Parametern. Sie müssen die Dokumentation Ihrer Implementierung überprüfen, um festzustellen, was sie unterstützt.

main()Es wird erwartet, dass Null zurückgegeben wird, um Erfolg anzuzeigen, und Nicht-Null, um Fehler anzuzeigen. Sie müssen eine returnAnweisung nicht explizit schreiben in main(): Wenn Sie main()ohne explizite returnAnweisung zurückkehren lassen, ist dies dasselbe, als hätten Sie geschrieben return 0;. Die folgenden zwei main()Funktionen verhalten sich gleich:

int main() { }
int main() { return 0; }

Es gibt zwei Makros, EXIT_SUCCESSund EXIT_FAILUREdefiniert in <cstdlib>das kann auch von zurückgegeben werden main()Erfolg und Misserfolg , um anzuzeigen, respectively.

Der von zurückgegebene Wert main()wird an die exit()Funktion übergeben, die das Programm beendet.

Beachten Sie, dass all dies nur beim Kompilieren für eine gehostete Umgebung gilt (informell eine Umgebung, in der Sie über eine vollständige Standardbibliothek verfügen und auf einem Betriebssystem Ihr Programm ausgeführt wird). Es ist auch möglich, ein C ++ - Programm für eine freistehende Umgebung (z. B. einige Arten eingebetteter Systeme) zu kompilieren. In diesem Fall sind Start und Beendigung vollständig implementierungsdefiniert und eine main()Funktion ist möglicherweise nicht einmal erforderlich. Wenn Sie jedoch C ++ für ein modernes Desktop-Betriebssystem schreiben, kompilieren Sie für eine gehostete Umgebung.

James McNellis
quelle
1
IIRC sind die einzigen garantierten Rückgabewerte 0, EXIT_SUCCESS (gleicher Effekt wie 0) und EXIT_FAILURE. BEARBEITEN: Ah, OK, andere Statuswerte ungleich Null können zurückgegeben werden, jedoch mit implementierungsdefinierter Bedeutung. Es wird garantiert, dass nur EXIT_FAILURE in irgendeiner Weise als Fehlerwert interpretiert wird.
Derrick Turk
4
@Synetech: Die Frage fragt im ersten Satz: "Was ist die richtige Signatur der Hauptfunktion in C ++?" und die Frage ist sowohl mit [c ++] als auch mit [c ++ - faq] markiert. Ich kann nicht anders, wenn Java- oder C # -Benutzer (oder andere) immer noch verwirrt sind. C # muss Maineine statische Elementfunktion sein, da es nicht einmal Nichtmitgliedsfunktionen enthält. Sogar C89 muss mainzurückkehren int. Ich bin mit K & R C nicht ausreichend vertraut, um die genauen Regeln zu kennen, aber ich würde vermuten, dass es auch eine mainRückgabe erfordert , intda mainohne Rückgabetyp etwas üblich war und kein Typ = intin K & R impliziert .
James McNellis
3
@Suhail: Weil der Sprachstandard besagt, dass der Rückgabetyp sein soll int.
James McNellis
1
@Suhail: Ja. Ihr Code ist in C ++ nicht korrekt und viele Compiler lehnen Ihren Code ab.
James McNellis
2
@Suhail: Visual C ++ erlaubt einen voidRückgabetyp als Spracherweiterung . Zu den Compilern, die dies nicht zulassen, gehören GCC und Comeau.
James McNellis
15

Aus Standarddokumenten., 3.6.1.2 Hauptfunktion ,

Es muss einen Rückgabetyp vom Typ int haben, ansonsten ist sein Typ implementierungsdefiniert. Alle Implementierungen müssen beide der folgenden Definitionen von main zulassen:

int main() { / ... / } und int main(int argc, char* argv[]) { / ... / }

In der letzteren Form argcist die Anzahl der Argumente anzugeben , die aus der Umgebung, in der das Programm ausgeführt wird, an das Programm übergeben werden. Wenn argc ungleich Null ist, werden diese Argumente in argv [0] bis argv [argc-1] als Zeiger auf die Initiale angegeben Zeichen von nullterminierten Multibyte-Zeichenfolgen .....

Hoffentlich hilft das..

liaK
quelle
2
Gibt es einen bestimmten Grund, warum der Rückgabetyp von mainsein sollte int?
Suhail Gupta
1
@SuhailGupta: Damit der aufrufende Prozess weiß, ob dieser Prozess als erfolgreich angesehen werden sollte oder nicht. Zulassen voidbricht dieses Modell. Es macht nicht einmal wirklich Sinn, wenn Sie es als "immer für Erfolg halten" bezeichnen würden. Weil Sie nicht sagen konnten, ob der Prozess tatsächlich fehlgeschlagen ist, haben Sie es wirklich geschafft? Nein, komm zurück int.
Leichtigkeitsrennen im Orbit
4

Der genaue Wortlaut des neuesten veröffentlichten Standards (C ++ 14) lautet:

Eine Implementierung muss beides ermöglichen

  • eine Funktion der ()Rückgabe intund

  • eine Funktion von (int, Zeiger auf Zeiger auf char)Rückkehrint

als die Art von main.

Dies macht deutlich, dass alternative Schreibweisen zulässig sind, solange der Typ mainder Typ ist int()oder int(int, char**). Daher sind auch folgende zulässig:

  • int main(void)
  • auto main() -> int
  • int main ( )
  • signed int main()
  • typedef char **a; typedef int b, e; e main(b d, a c)
MM
quelle
1
NB. Ich habe diese Antwort wie in Kommentaren zu einem anderen Thread gepostet. Jemand hat versucht, diesen Thread als Beweis zu zitieren, der int main(void)in C ++ nicht korrekt war.
MM
3
@Stargateur auto main() -> inthat keinen abgeleiteten Rückgabetyp. Achten Sie auf das {in "(auto main () {... ist nicht erlaubt)" und lernen Sie bitte, wenn Sie noch nicht genug wissen, um etwas Sinnvolles hinzuzufügen.
3

Die beiden gültigen Netze sind int main()und int main(int, char*[]). Alles andere kann kompiliert werden oder nicht. Wenn mainein Wert nicht explizit zurückgegeben wird, wird implizit 0 zurückgegeben.

Steinmetall
quelle
1
Ich habe noch nie gesehen, dass Code nicht kompiliert wird, wenn ich den Rückgabetyp mainals ungültig erwähne . Gibt es einen bestimmten Grund, warum der Rückgabetyp von main int sein sollte?
Suhail Gupta
4
Die Sprachspezifikation besagt, dass main den Rückgabetyp int haben muss. Jeder andere von Ihrem Compiler zugelassene Rückgabetyp ist eine compilerspezifische Erweiterung. Grundsätzlich bedeutet die Verwendung von void, dass Sie in einer Sprache programmieren, die C ++ ähnelt, jedoch nicht C ++.
Steinmetz
2
Der Grund, warum der Standard einen intRückgabetyp erfordert, mainist, dass dieser Wert als Exit-Code des Programms an die Shell übergeben wird und einen sherwartet int.
uckelman
Vielleicht liegt der Grund in der Disziplin? Es kann mehr als einen Pfad geben. Wenn der Rückgabetyp ist void, sind alle still. Mit müssen intwir den spezifischen Exit-Wert für jede Rückgabe von definieren main.
Andreas Spindler
2

Details zu Rückgabewerten und deren Bedeutung

Per 3.6.1 ( [basic.start.main]):

Eine return-Anweisung in mainhat den Effekt, dass die mainFunktion verlassen wird (Objekte mit automatischer Speicherdauer werden zerstört) und std::exitder Rückgabewert als Argument aufgerufen wird. Wenn die Kontrolle das Ende erreicht, mainohne auf eine returnAnweisung zu stoßen , bewirkt dies die Ausführung

return 0;

Das Verhalten von std::exitwird in Abschnitt 18.5 ( [support.start.term]) beschrieben und beschreibt den Statuscode:

Schließlich wird die Kontrolle an die Hostumgebung zurückgegeben. Wenn der Status Null ist oder EXIT_SUCCESSeine implementierungsdefinierte Form der Statusbeendigung erfolgreich zurückgegeben wird. Wenn der Status "Ist" lautet EXIT_FAILURE, wird eine implementierungsdefinierte Form des Status "Nicht erfolgreiche Beendigung" zurückgegeben. Andernfalls ist der zurückgegebene Status implementierungsdefiniert.

Ben Voigt
quelle