main() rekursiv aufrufen?



  • Mir ist eben in den Sinn gekommen, die main-funktion mal rekursiv aufzurufen. Hierzu ein kleines Beispiel:

    #include <iostream>
    using namespace std;
    
    int main() {
        static int b = 0;
        cout << ++b << "\n";
        main();
    }
    

    Bei mir wird b auf 65 072 erhöht und stürzt dann ab. Was passiert denn da?
    Dann hätte ich noch ein paar weitere Fragen dazu:

    Warum stürzt einem das Programm ab, wenn man main() rekursiv aufruft? Wieso funktioniert das anscheinend nur 65 072 mal? Sollte man das nicht tun?

    Wär nett wenn mich jmd aufklären könnte^^



  • WTF! Diese Idee von Missbrauch ist mir noch nie in den Sinn gekommen. Mich interessiert die Antwort auch.

    Edot: Bei mir knallt es bei 4000 mit Stack Overflow 🙂



  • Du darfst main() nicht rekursiv aufrufen. Aber das macht nichts, ein sinnvolles Beispiel dafür gibt es ohnehin nicht.

    Dein Problem betrifft ohnehin nicht main() im Speziellen, sondern Rekursion. Stichwort Stack-Overflow.



  • In C ist das erlaubt. Gibt es eigentlich eine Begründung dafür, warum C++ das verbietet?



  • Nexus schrieb:

    Du darfst main() nicht rekursiv aufrufen. Aber das macht nichts, ein sinnvolles Beispiel dafür gibt es ohnehin nicht.

    Dein Problem betrifft ohnehin nicht main() im Speziellen, sondern Rekursion. Stichwort Stack-Overflow.

    Schön und gut, aber wieso ists denn jetzt verboten main rekursiv aufzurufen?



  • Ich wüsste auch gerne warum es verboten ist, abgesehen von dem Problem, dass es unschön und rekursiv ist?



  • Im Standard heisst es:

    The function main shall not be used (3.2) within a program.

    Auf Deutsch: du darfst sie nicht aufrufen. Der Grund dafür ist mir allerdings schleierhaft.



  • ccc schrieb:

    In C ist das erlaubt.

    Bist du dir da sicher? Steht das so im C-Standard oder tun das lediglich die IOCCC-Leute?

    ccc schrieb:

    Gibt es eigentlich eine Begründung dafür, warum C++ das verbietet?

    Wahrscheinlich um der Implementierung irgendwelche Freiheiten zu lassen. Gibt es irgendeinen Grund, es zu erlauben?

    Übrigens, aus dem C++-Standard:

    §3.6.1/3 Main function schrieb:

    The function main shall not be used (3.2) within a program.

    §3.2/2 One definition rule schrieb:

    An object or non-overloaded function is used if its name appears in a potentially-evaluated expression.



  • Es gibt keinen wirklich schluessigen Grund. Es ist deshalb verboten damit Implementierungen am Anfang von Main initialisierungen vornehmen koennen. Nur ist es ja kein Problem diese in eine andere Funktion zu legen und von dort aus dann main aufzurfen (VC++ verwendet zB _CrtMainStartup oder so).

    Es gibt aber keinen Grund warum man das unbedingt tun muss, deshalb ists eigentlich kein Thema.

    In C ist es zB erlaubt.



  • Da quote ich mal jemanden :

    Jemand schrieb:

    Think about a normal function call(one that doesn't call main). First the program may load the stack with values, jump to the function address, possibly load more values on the stack execute some code and then return...When the function returns it frees up all of its stack resources...Hence the term local variables...Local to the function, stored on the stack...Now a main function only returns when the program exits...So each time you call main you load up the stack with its associated values only freeing them all(all of main's) when the program exits....Do you now see why its not a good idea?



  • @Felixxx Jetzt bin ich überzeugt 🙂

    Edit lieber so:

    void foo(){
    	static int b = 0;
    	cout << ++b << "\n"; 
    }
    
    int main(){ 
        while(1)
    		foo(); 
    }
    


  • Ich bin noch nicht überzeugt. Warum kann der Compiler nicht intern in einer anderen Funktion starten und dann main aufrufen? So viel Flexibilität ist bei C++ nichts aussergewöhnliches.

    Aber ich hinterfrage zu viel. Warum HighLigerBiMBam drei Posts geschrieben hat, ohne etwas brauchbares auszusagen finde ich auch mehr als fragwürdig.



  • Weil ich das Thema interessant fand und aus tiefster Überzeugung Spammer bin. Und anscheinend kann der Compiler dies nicht auslagern.

    Edit: Ich kann derzeit auch nur schwer beurteilen, ob dieses "Feature" ein Vor- oder Nachteil gegenüber C ist. Aber die Erklärung hat mich geholfen zu verstehen warum in C++ dies nicht gemacht wird. Dies erklärt aber nicht warum man es nicht in eine Funktion Compilerseitig erstellt.



  • also zunächst mal ist es erlaubt, auch in C++!
    Im Standard steht ausdrücklich "shall not" und nicht "must not".
    Es ist also lediglich eine Empfehlung main nicht aufzurufen.

    Die Erklärung, dass main lokale Variablen erst bei Programmende freigibt ist Dünnes.
    main wird genau wie jede andere C-Funktion über die C Calling Convention aufgerufen. Lokale Variablen und Parameter liegen auf dem Stack und werden beim return wieder aufgeräumt.

    Die main Funktion stürzt aus dem gleichen Grund ab, aus dem auch jede andere Funktion mit unendlicher Rekursion abstürzt: Stack Overflow.

    Da bei einer unendlichen Rekursion das return NIE erreicht wird, wird auch der Stack nicht aufgeräumt.
    Allerdings kann auch bei endlicher Rekursion ein Stack Overflow auftreten, wenn die Rekursion einfach zu tief ist.



  • Okay, das wollte ich wissen, dankeschön^^



  • Rekursion -> Stack Overflow -> klar, aber warum ist bei der Rekursion von Main der Stack so viel schneller voll, als wenn ich es in eine Funktion auslagere? Wieviel zusätzliche Initialisierungsarbeiten leistet die main?



  • DrakoXP schrieb:

    also zunächst mal ist es erlaubt, auch in C++!
    Im Standard steht ausdrücklich "shall not" und nicht "must not".
    Es ist also lediglich eine Empfehlung main nicht aufzurufen.

    Nein, "shall" bedeutet im C++-Standard schon "muss" (sofern sich die Implementierung an den Standard hält und portables Programmieren ermöglichen will). Den Ausdruck findest du immer wieder.

    DrakoXP schrieb:

    main wird genau wie jede andere C-Funktion über die C Calling Convention aufgerufen.

    Der Standard sagt, die Linkage von main() sei implementation-defined. Dem entnehme ich, dass die Implementierungsabhängigkeit auch auf die Calling Convention zutrifft.

    DrakoXP schrieb:

    Die Erklärung, dass main lokale Variablen erst bei Programmende freigibt ist Dünnes. [...] Lokale Variablen und Parameter liegen auf dem Stack und werden beim return wieder aufgeräumt.

    Ja, und zufällig leitet ein return in main() das Programmende ein.

    Incocnito schrieb:

    Okay, das wollte ich wissen, dankeschön^^

    Vergiss das lieber wieder, es ist nämlich zu einem grossen Teil falsch.



  • Was hindert dich daran, es selber nachzuschauen?
    Laut Standard: nichts
    Laut g++: Nichts, das wird in _GLOBAL__I_main erledigt.
    Laut deinem proprietären visuellen Compiler: wahrscheinlich alles (ich weiss es nicht)

    Klar, der Standard erlaubt es, weshalb das Programm von Incocnito funktioniert. Aber benutzen sollte man es dennoch nicht.



  • Hmm wenn du meinst, Nexus. Hat sich nur so schön plausibel und einfach angehört^^

    ps. Du hast jetzt schon 8000 Beiträge, Respekt 😉



  • 😑 schrieb:

    Was hindert dich daran, es selber nachzuschauen?
    Laut Standard: nichts
    Laut g++: Nichts, das wird in _GLOBAL__I_main erledigt.
    Laut deinem proprietären visuellen Compiler: wahrscheinlich alles (ich weiss es nicht)

    Klar, der Standard erlaubt es, weshalb das Programm von Incocnito funktioniert. Aber benutzen sollte man es dennoch nicht.

    hehe das deutlich früher abrauchen lag am debug mode 🙄 Macht keinen Unterschied im Release... Alles klar danke.



  • Nur der Vollständigkeit halber:
    Verlangt Rekursion eigentlich zwingend eine Abruchbedingung, oder ist rein theoretisch auch das gezeigte Beispiel eine Rekursion?

    (Ich meine das eher im mathematischen Sinne; ist ja klar, dass eine Programmfunktion ohne Abbruchbedingung wohl keinen Sinn ergibt, und da meine ich nicht einen stack overflow...)


Anmelden zum Antworten