Heftige Reaktion bei kleinem Schnitzer...



  • macht es denn irgendeinen sinn das das nicht zum compilerfehler führt?



  • 😕 Wenn ich den gezeigten Quellcode in MSVC 2012 ausführe bekomme ich:

    1 Error: error C4716: 'run_comparison_script' : must return a value
    1 Warning: warning C4100: 'script' : unreferenced formal parameter

    Was verwendet ihr den für einen Compiler?



  • GCC.



  • Sone schrieb:

    GCC.

    Dann mal +1 für MSVC 😃



  • War ja klar...Billigcompiler.



  • out schrieb:

    Sone schrieb:

    GCC.

    Dann mal +1 für MSVC 😃

    Lol. Dafür das er mit dem Standard inkompatibel ist? 👎

    GCC tut nur seine Pflicht :p



  • Darf ein Compiler nur als Fehler auslegen, was tatsächlich durch den Standard untersagt ist?



  • Wenn ich mich nicht taeusche, darf nur einen Fehler ausgeben, was wirklich ill-formed ist. Das Programm ist ja Standard-Konform, wenn auch mit undefiniertem Verhalten, also muss es kompilieren. Warnen dagegen darf ein Compiler so viel er will.

    In der Hinsicht hat MSVC hier wirklich einen Bug:

    #include <iostream>
    
    void foo()
    {
    	int i;
    	i = (++i)*(--i)%60;
    	std::cout << i;
    }
    
    int bar()
    {
    	int i;
    	i = (++i)*(--i)%60;
    	return i;
    }
    
    int retNoValue1()
    {}
    
    int retNoValue2()
    {
    	foo();
    }
    
    int retNoValue3()
    {
    	if(bar() % 8)
    	{
    		return 0;
    	}
    }
    
    int main()
    {
    	retNoValue1();
    	retNoValue2();
    	retNoValue3();
    }
    
    1>------ Erstellen gestartet: Projekt: Test, Konfiguration: Debug Win32 ------
    1>Der Buildvorgang wurde am 28.10.2012 09:48:03 gestartet.
    1>InitializeBuildStatus:
    1>  Aktualisieren des Timestamps von "Debug\Test.unsuccessfulbuild".
    1>ClCompile:
    1>  main.cpp
    1>p:\tmp\test\main.cpp(6): warning C4700: Die nicht initialisierte lokale Variable "i" wurde verwendet.
    1>p:\tmp\test\main.cpp(13): warning C4700: Die nicht initialisierte lokale Variable "i" wurde verwendet.
    1>p:\tmp\test\main.cpp(18): error C4716: 'retNoValue1': Muss einen Wert zurückgeben
    1>p:\tmp\test\main.cpp(23): error C4716: 'retNoValue2': Muss einen Wert zurückgeben
    1>p:\tmp\test\main.cpp(31): warning C4715: "retNoValue3": Nicht alle Steuerelementpfade geben einen Wert zurück.
    1>
    1>Fehler beim Erstellen
    1>
    1>Verstrichene Zeit 00:00:00.79
    ========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========
    

    Bei den uninitialisierten Variablen warnt er erwartungsgemaess, auch bei retNoValue3 warnt er richtig. Aber bei retNoValue1 und retNoValue2 ist der Fehler falsch, weil das trotzdem nicht ill-formed ist.
    Getestet auf MSVC 2010 Professional, deaktivieren der MS-Spracherweiterungen macht keinen Unterschied. VS2012 kann ich grad nicht benutzten, weil mir gestern durch einen Stromausfall eine Platte abgeraucht ist (nach nicht mal 48 h Betrieb, hatte meinen PC gerade vom aufruesten wieder :(). Koennt das mal jemand anderes testen, obs da richtig geht?



  • Ich finde es aber ehrlich gesagt angemessen, dass er nicht kompiliert. Es gibt doch wirklich keinen Fall, wo das sinnvoll sein könnte.



  • Natuerlich waere es absolut nicht sinnvoll, wuerde es kompilieren. Tatsache ist aber, dass das Programm nicht ill-formed ist, weshalb der Compiler C4716 eigentlich genauso als Warnung behandlen muesste wie C4715. Ob ich dann 'Warnungen wie Fehler behandeln' anschalte ist meine Sache.


  • Mod

    Eisflamme schrieb:

    Ich finde es aber ehrlich gesagt angemessen, dass er nicht kompiliert. Es gibt doch wirklich keinen Fall, wo das sinnvoll sein könnte.

    int foo(int x)
    {
     if (x>0) return 1;
     if (x<0) return 0;
    }
    

    Fehler? Warnung? Korrektes Programm?

    void foobar()
    {
     exit(0);
    }
    
    int bar()
    {
     foobar();
    }
    

    Fehler? Warnung? Korrektes Programm?



  • SeppJ schrieb:

    int foo(int x)
    {
     if (x>0) return 1;
     if (x<0) return 0;
    }
    

    Fehler? Warnung? Korrektes Programm?

    warning C4715: 'foo' : not all control paths return a value

    SeppJ schrieb:

    void foobar()
    {
     exit(0);
    }
    
    int bar()
    {
     foobar();
    }
    

    Fehler? Warnung? Korrektes Programm?

    error C4716: 'bar' : must return a value



  • SeppJ:
    Wenn der Compiler ermitteln kann, dass kein return erfolgt, sollte er imo einen Fehler ausgeben. Wenn er es nicht mit Sicherheit sagen kann wie in Deinem Programm, dann sollte er die Schnauze halten bzw. eben eine Warnung ausgeben.

    Denn in ersterem Fall kann es imo keinen sinnvollen Fall geben. Funktionen, die einen Rückgabetyp haben, müssen etwas zurückgeben. Was sollte denn die Semantik einer Nicht-Rückgabe sein, wenn das Verhalten undefiniert ist?

    Edit: Wie out zeigt macht es der MSVC auch genau so, wie ich es für sinnvoll erachte.


  • Mod

    out schrieb:

    SeppJ schrieb:

    int foo(int x)
    {
     if (x>0) return 1;
     if (x<0) return 0;
    }
    

    Fehler? Warnung? Korrektes Programm?

    warning C4715: 'foo' : not all control paths return a value

    Ok, meinetwegen. Nervige Meldung, da ich die Funktion doch wissentlich nie mit 0 aufrufe.

    SeppJ schrieb:

    void foobar()
    {
     exit(0);
    }
    
    int bar()
    {
     foobar();
    }
    

    Fehler? Warnung? Korrektes Programm?

    error C4716: 'bar' : must return a value

    Dies ist aber ein reguläres Programm, welches nun nicht mehr compiliert. In allen erdenklichen Fällen wäre der Ablauf dieses Programms wohldefiniert.

    Eisflamme schrieb:

    Was sollte denn die Semantik einer Nicht-Rückgabe sein, wenn das Verhalten undefiniert ist?

    Fragst du gerade nach der Semantik von undefiniertem Verhalten? 😕

    Wenn der Compiler ermitteln kann, dass kein return erfolgt, sollte er imo einen Fehler ausgeben. Wenn er es nicht mit Sicherheit sagen kann wie in Deinem Programm, dann sollte er die Schnauze halten bzw. eben eine Warnung ausgeben.

    Der Punkt meiner Beispielprogramme ist: Das ist praktisch unmöglich festzustellen! Bei all den Schweinereien die in C++ erlaubt sind, könnte sogar selbstveränderlicher Code vorkommen oder ein nebenläufiges Programm funkt in der Funktion irgendwie dazwischen. Das ist sicherlich der Grund, wieso der Standard so formuliert ist.



  • Und welchen Sinn ergibt eine Funktion, die unter gar keinen Umständen etwas zurückgibt? Genau, keinen.


  • Mod

    Eisflamme schrieb:

    Und welchen Sinn ergibt eine Funktion, die unter gar keinen Umständen etwas zurückgibt? Genau, keinen.

    Vielleicht muss sie eine bestimmte Schnittstelle erfüllen?

    void needs_callback(int (*foo)())
    {
     int i = foo();
    }
    
    int just_for_debugging()
    {
     std::cerr << "Callback called! Exiting now!\n";
     exit(0);
    }
    
    int main()
    {
     needs_callback(&just_for_debugging);
    }
    

    Warnung? Fehler? Korrektes Programm?

    Soll ich weiter machen mit den Beispielen? Es ist Sonntag und ich habe Zeit 🕶



  • Im Endeffekt ist das wieder so ein Teil von C++, wo der Programmierer halt die Verantwortung in die Hände gedrückt bekommt. Wenn jemand bei jedem kleinsten Fehler Fehlermeldungen braucht, weil er sonst die Fehler nicht findet, hat bei C/C++ nix zu suchen. IMO.

    Außerdem müsste man noch definieren, wann ein Fehler und Wann eine Warnung kommt, was dann wieder in einem Krieg ausarten würde. 😃

    Wie auch immer, man sieht: VC++ macht es falsch (nicht standardkonform), und dazu (im obigen Fall) auch noch unsinnig.



  • SeppJ:
    Ja und wenn der Rückgabewert nicht von dem, der die Schnittstelle erzwingt, verwertet wird, ist die Schnittstelle wohl nicht besonders schön designed. Liegt das in eigener Hand, würde ich sie verbessern. Liegt das in fremder Hand kann man sich doch gar nicht so sicher sein, was mit dem Rückgabewert passiert. Und dann sollte man wohl dafür Sorge tragen, dass auch ein Wert (und sei es Dummy) zurückgegeben wird.

    Wenn ich eine Funktion mit Rückgabetyp habe, schreibe ich dort auch ein return rein. Und ich tue das auch dann, wenn ich weiß, dass der Rückgabewert nicht verwendet wird. Es hat doch keinen praktischen Vorteil es nicht zu tun, außer dass man höchstens unnötigen Code hinschreibt. Ist aber die Schnittstelle schon so entwickelt, dass Rückgabe erforderlich ist, so liegt der Designfehler hier nicht darin ein unnötiges return zu schreiben, sondern in meinen Augen in der Schnittstelle.

    Hast Du ein praktisches Beispiel (muss ja kein Code sein), in welchem eine Rückgabetyp einer Funktion bei einer Schnittstelle gefordert wird, obwohl man guten Gewissens das return auslassen kann?



  • Dafuer gibts doch jetzt [noreturn]. Ergo gueltiges Programm.


  • Mod

    Eisflamme schrieb:

    Hast Du ein praktisches Beispiel (muss ja kein Code sein), in welchem eine Rückgabetyp einer Funktion bei einer Schnittstelle gefordert wird, obwohl man guten Gewissens das return auslassen kann?

    main.

    Kellerautomat schrieb:

    Dafuer gibts doch jetzt [noreturn]. Ergo gueltiges Programm.

    Danke, das bringt mich auf noch eine Idee:

    int does_not_return()
    {
     for (;;);
    }
    

    Warnung? Fehler? Gültiges Programm?

    (Dieser Fall ist insofern interessant, da der Compiler annehmen darf, dass nebeneffektfreie Endlosschleifen doch terminieren, aufgrund einer obskuren Klausel im Standard, die fast niemand kennt und die ich gerade nicht suchen mag. Falls das zu verwirrend ist, möge man sich einfach eine Ausgabe in der Schleife denken :p )


Anmelden zum Antworten