it-swarm.com.de

Ist main () wirklich der Start eines C ++ - Programms?

Der Abschnitt $ 3.6.1/1 aus dem C++ Standard lautet:

Ein Programm muss eine globale Funktion mit dem Namen main enthalten, die als start des Programms bezeichnet wird.

Betrachten Sie nun diesen Code,

int square(int i) { return i*i; }
int user_main()
{ 
    for ( int i = 0 ; i < 10 ; ++i )
           std::cout << square(i) << endl;
    return 0;
}
int main_ret= user_main();
int main() 
{
        return main_ret;
}

Dieser Beispielcode macht das, was ich vorhabe, dh er gibt das Quadrat der ganzen Zahlen von 0 bis 9 aus vor Eingabe der main() -Funktion, die der "Start" sein soll des Programms.

Ich habe es auch mit der Option -pedantic, GCC 4.5.0 kompiliert. Es gibt keinen Fehler, nicht einmal eine Warnung!

Also meine Frage ist,

Ist dieser Code wirklich Standardkonform?

Wenn es standardkonform ist, macht es dann nicht ungültig, was der Standard sagt? main() ist kein Programmstart! user_main() wird vor main() ausgeführt.

Ich verstehe, dass zum Initialisieren der globalen Variablen main_ret Die Funktion use_main() zuerst ausgeführt wird, aber das ist eine ganz andere Sache. der Punkt ist, dass es tut die zitierte Anweisung $ 3.6.1/1 aus dem Standard ungültig macht, da main() NICHT der Start ist des Programms; es ist in der Tat das Ende von diesem Programm!


BEARBEITEN:

Wie definieren Sie das Wort "Start"?

Es läuft auf die Definition der Phrase "Start des Programms" hinaus. Wie genau definieren Sie es?

130
Nawaz

Nein, C++ unternimmt viele Dinge, um die Umgebung vor dem Aufruf von main festzulegen. main ist jedoch der offizielle Start des "benutzerdefinierten" Teils des C++ - Programms.

Einige der Umgebungskonfigurationen können nicht gesteuert werden (wie der ursprüngliche Code zum Einrichten von std :: cout), andere hingegen können wie statische globale Blöcke gesteuert werden (zum Initialisieren statischer globaler Variablen) Kontrolle vor Main, Sie haben keine volle Kontrolle über die Reihenfolge, in der die statischen Blöcke initialisiert werden.

Nach main hat Ihr Code konzeptionell "die volle Kontrolle" über das Programm, in dem Sinne, dass Sie sowohl die auszuführenden Anweisungen als auch die Reihenfolge angeben können, in der sie ausgeführt werden sollen. Multithreading kann die Reihenfolge der Codeausführung ändern. Sie haben jedoch weiterhin die Kontrolle über C++, da Sie angegeben haben, dass Codeabschnitte (möglicherweise) nicht in der richtigen Reihenfolge ausgeführt werden sollen.

82
Edwin Buck

Sie lesen den Satz falsch.

Ein Programm muss eine globale Funktion namens main enthalten , die der festgelegte Start des Programms ist.

Der Standard definiert das Wort "Start" für den Rest des Standards. Es heißt nicht, dass kein Code ausgeführt wird, bevor main aufgerufen wird. Es heißt, dass der Start des Programms auf der Funktion main liegt.

Ihr Programm ist kompatibel. Ihr Programm wurde erst nach dem Start von main "gestartet". Der Konstruktor wird aufgerufen, bevor Ihr Programm gemäß der Definition von "start" im Standard "startet", aber das spielt kaum eine Rolle. Eine Menge Code wird ausgeführt, bevor main in jedem Programm aufgerufen wird , nicht nur in diesem Beispiel.

Zu Diskussionszwecken wird Ihr Konstruktorcode vor dem 'Start' des Programms ausgeführt und entspricht voll und ganz dem Standard.

87
Adam Davis

Ihr Programm wird nicht verlinkt und daher nicht ausgeführt, es sei denn, es gibt ein Hauptprogramm. Main () bewirkt jedoch nicht den Start der Programmausführung, da Objekte auf Dateiebene Konstruktoren haben, die zuvor ausgeführt werden, und es wäre möglich, ein gesamtes Programm zu schreiben, das seine Lebensdauer hat, bevor main () erreicht ist, und main sich selbst ausführen zu lassen ein leerer Körper.

Um dies zu erzwingen, müssten Sie in Wirklichkeit ein Objekt, das vor main erstellt wurde, und dessen Konstruktor haben, um den gesamten Programmablauf aufzurufen.

Schau dir das an:

class Foo
{
public:
   Foo();

 // other stuff
};

Foo foo;

int main()
{
}

Der Ablauf Ihres Programms würde sich effektiv aus Foo::Foo() ergeben.

23
CashCow

Sie haben die Frage ebenfalls mit "C" markiert. Wenn Sie also ausschließlich von C sprechen, sollte Ihre Initialisierung gemäß Abschnitt 6.7.8 "Initialisierung" des ISO-C99-Standards fehlschlagen.

In diesem Fall scheint die Einschränkung Nr. 4 am relevantesten zu sein, die besagt:

Alle Ausdrücke in einem Initialisierer für ein Objekt mit statischer Speicherdauer müssen konstante Ausdrücke oder Zeichenfolgenliterale sein.

Die Antwort auf Ihre Frage lautet also, dass der Code nicht dem C-Standard entspricht.

Sie möchten wahrscheinlich das "C" -Tag entfernen, wenn Sie sich nur für den C++ - Standard interessieren.

15
Remo.D

In Abschnitt 3.6 wird das Zusammenspiel von main und dynamischen Initialisierungen sehr deutlich. Der "festgelegte Start des Programms" wird nirgendwo anders verwendet und beschreibt nur die allgemeine Absicht von main(). Es macht keinen Sinn, diesen einen Satz in einer normativen Weise zu interpretieren, die den detaillierteren und klareren Anforderungen in der Norm widerspricht.

10
aschepler

Der Compiler muss häufig Code hinzufügen, bevor main () standardkonform ist. Da der Standard vorschreibt, dass die Initalisierung von Globals/Statics durchgeführt werden muss , bevor das Programm ausgeführt wird. Dasselbe gilt, wie erwähnt, für Konstruktoren von Objekten, die im Dateibereich (Globals) platziert sind.

Daher ist die ursprüngliche Frage auch für C relevant , da Sie in einem C-Programm immer noch die globale/statische Initialisierung durchführen müssen, bevor das Programm gestartet werden kann.

Die Standards setzen voraus, dass diese Variablen durch "Magie" initialisiert werden, da sie nicht angeben , wie sie vor der Programminitialisierung gesetzt werden sollen. Ich denke, sie betrachteten das als etwas, das außerhalb des Anwendungsbereichs eines Programmiersprachenstandards liegt.

Bearbeiten: Siehe zum Beispiel ISO 9899: 1999 5.1.2:

Alle Objekte mit statischer Speicherdauer müssen vor dem Programmstart initialisiert (auf ihre Anfangswerte gesetzt) ​​werden. Die Art und der Zeitpunkt einer solchen Initialisierung sind ansonsten nicht spezifiziert.

Die Theorie, wie diese "Magie" zu bewerkstelligen war, reicht zurück bis zu Cs Geburt, als es sich um eine Programmiersprache handelte, die nur für das UNIX-Betriebssystem auf RAM-basierten Computern verwendet werden sollte. Theoretisch wäre das Programm in der Lage, alle vorinitialisierten Daten aus der ausführbaren Datei in den Arbeitsspeicher zu laden, während das Programm selbst in den Arbeitsspeicher hochgeladen wurde.

Seitdem haben sich Computer und Betriebssystem weiterentwickelt, und C wird in einem viel größeren Bereich als ursprünglich angenommen eingesetzt. Ein modernes PC-Betriebssystem verfügt über virtuelle Adressen usw., und alle eingebetteten Systeme führen Code aus dem ROM und nicht aus dem RAM aus. Es gibt also viele Situationen, in denen RAM nicht "automagisch" gesetzt werden kann.

Außerdem ist der Standard zu abstrakt, um etwas über Stacks und Prozessspeicher usw. zu wissen. Diese Dinge müssen ebenfalls ausgeführt werden, bevor das Programm gestartet wird.

Daher hat so ziemlich jedes C/C++ - Programm einen Init/"Copy-Down" -Code, der ausgeführt wird, bevor main aufgerufen wird, um den Initialisierungsregeln der Standards zu entsprechen.

Beispielsweise haben eingebettete Systeme in der Regel die Option "Nicht-ISO-konformer Start", bei der die gesamte Initialisierungsphase aus Leistungsgründen übersprungen wird und der Code dann direkt von main aus gestartet wird. Solche Systeme entsprechen jedoch nicht den Standards, da Sie sich nicht auf die Initialisierungswerte globaler/statischer Variablen verlassen können.

9
Lundin

main () ist eine Benutzerfunktion, die von der C-Laufzeitbibliothek aufgerufen wird.

siehe auch: Vermeiden des Haupt- (Einstiegspunkt) in einem C-Programm

4
sylvanaar

Ihr "Programm" gibt einfach einen Wert aus einer globalen Variablen zurück. Alles andere ist Initialisierungscode. Somit gilt der Standard - Sie haben nur ein sehr einfaches Programm und eine komplexere Initialisierung.

4
Zac Howland

Scheint wie eine englische Semantik zu streiten. Das OP bezeichnet seinen Codeblock zuerst als "Code" und später als "Programm". Der Benutzer schreibt den Code und dann schreibt der Compiler das Programm.

2
dSerk

main wird aufgerufen, nachdem alle globalen Variablen initialisiert wurden.

Was der Standard nicht spezifiziert, ist die Reihenfolge der Initialisierung aller globalen Variablen aller Module und statisch verknüpften Bibliotheken.

1
vz0

Ja, main ist der "Einstiegspunkt" für jedes C++ - Programm, mit Ausnahme von implementierungsspezifischen Erweiterungen. Trotzdem passieren einige Dinge vor der Hauptinitialisierung, insbesondere die globale Initialisierung für main_ret.

0
Fred Nurk