"ungültige Gleitkommaoperation" in Funktion, die nichts berechnet



  • Soweit ich weiß, ist das tatsächlich undefiniert.

    Technische Ursache des Fehlers ist, daß BCC Gleitkomma-Rückgabewerte über den FPU-Stack zurückgibt. Für folgenden Code

    double foo (void)
    {
        return 0.0;
    }
    int main (void)
    {
        foo ();
    }
    

    generiert BCC das:

    @@foo$qv	proc	near
    ?live16385@0:
    @1:
    	fld       qword ptr [@2]
    @4:
    @3:
    	ret 
    	align 4        
    @2:
    	db 0,0,0,0,0,0,0,0
    ...
    @_main	proc	near
    ?live16386@0:
    @5:
    	call      @@foo$qv
    	fstp      st(0) // <--
    	xor       eax,eax
    @7:
    @6:
    	ret
    

    Wenn foo() keinen Wert zurückgibt, wird natürlich auch nie fld aufgerufen, und der Aufruf von fstp invalidiert den FPU-Stack-Pointer.



  • audacia schrieb:

    Soweit ich weiß, ist das tatsächlich undefiniert.

    double foo (void)
    {
        return 0.0;
    }
    int main (void)
    {
        foo ();
    }
    

    Was?
    Ich kann mir nicht vorstellen, dass das undefiniert sein soll. Dann dürfte ja sowas hier auch nicht gehen:

    int main()
    {
    printf("hallo");
    }
    

    Printf gibt auch was zurück, was ich aber in dem Fall ignoriere. Und das ist doch sicherlich nicht undefiniert, oder? Meiner Meinung nach kann man doch Returnvalues einfach ignorieren, wenn man sie nciht braucht, oder?
    Oder ist das für Gleitkomma anders oder ein Problem vom BCC?



  • Maxi schrieb:

    audacia schrieb:

    Soweit ich weiß, ist das tatsächlich undefiniert.

    double foo (void)
    {
        return 0.0;
    }
    int main (void)
    {
        foo ();
    }
    

    Was?
    Ich kann mir nicht vorstellen, dass das undefiniert sein soll.

    Ist es auch nicht. Mein Satz bezog sich, wie im Kontext offensichtlich wird, auf dein Codebeispiel, nicht auf mein erst nachfolgend erwähntes, und die beiden unterscheiden sich ein wenig - du gibst nämlich keinen Wert zurück 😉

    Einen Rückgabewert zu verwerfen ist natürlich legitim.



  • @audacia:

    und wieso gibt er da ne warning und keinen fehler aus? gibts denn irgendwelche anwendungsbsp. (zumindest theoretische), in denen man das ausnutzen kann?

    msvc bringt hier brav ne fehlermeldung:
    error C4716: 'foo' : must return a value

    allerdings nutzt er den fpu-stack auch nicht, so erhalte ich mit return 0.; dann folgendes:
    (release-mode, debug-mode war zu viel müll dabei, als das es noch übersichtlich wäre ^^)

    __declspec(noinline) double foo() ;nur, damit er die fkt nicht inline macht und man gar nichts mehr sieht ;D
    {
    	return 0.;
    00C51000  fldz ; load floating point value zero             
    }
    

    bzw.

    __declspec(noinline) double foo()
    {
    	return 1.23;
    00AF1000  fld         qword ptr [__real@3ff3ae147ae147ae (0AF2108h)] 
                           ; load floating point value
    }
    

    zu fld/fldz konnte ich aber nicht wirklich was finden - scheint nur irgend nen floatingpoint-wert zu laden, aber iwie hab ich nicht so richtig die ahnung, wo das dann abgelegt werden sollte oO
    hat vll jmd nen link um mein (sehr) begrenztes asm-wissen zu erweitern? ^^

    bb



  • audacia schrieb:

    unskilled schrieb:

    ist nen sicheres zeichen, den compiler zu wechseln, wenn du bei so was nich ma ne warnung erhältst

    Das ist vielmehr ein Indiz, daß du mal auf Warnungen achten solltest. C++Builder emittiert in diesem Fall nicht zu Unrecht W8070.

    Ja, da hast Du recht (so hab ich es dann ja schließlich auch gefunden. Hatte halt noch diverse Testvariablen drin von früheren Debuggings, wo lauter Warnungen kamen, daß Variable xy nicht verwendet wird. Da ist das untergegangen. Hab den Code jetzt ein bißchen aufgeräumt, aber kann das nur step-by-step machen)
    Trotzdem, ein bißchen mehr Fehlermeldungen wären mir ja schon ganz lieb... Da tut man sich einfacher, wenn man nicht der Crack ist. Aber es ist, wie's ist...



  • susie schrieb:

    audacia schrieb:

    unskilled schrieb:

    ist nen sicheres zeichen, den compiler zu wechseln, wenn du bei so was nich ma ne warnung erhältst

    Das ist vielmehr ein Indiz, daß du mal auf Warnungen achten solltest. C++Builder emittiert in diesem Fall nicht zu Unrecht W8070.

    [...]
    Trotzdem, ein bißchen mehr Fehlermeldungen wären mir ja schon ganz lieb... Da tut man sich einfacher, wenn man nicht der Crack ist. Aber es ist, wie's ist...

    aber trotzdem sollte man sich von anfang an dran gewöhnen, warnungen zu beachten.
    auch sollte man niemals fkt ohne nen return-wert implementieren - selbst am anfang, wenn man nur mal grob ne skizze machen möchte - dann tut man das halt so:

    double foo()
    {
      assert(0); //TODO
      return 0.;
    }
    

    - man kann nach TODO suchen
    - beim testen bekommt man sofort eine fehlermeldung mit zeile etc und sieht sofort wieder, dass man dort noch was machen wollte...
    wenn man will, kann man so gar noch ein throw 0; oder so nach dem assert reinmachen, damit es auch im release-mode nicht zu bösen überraschungen und zur ewigen fehlersuche kommt, weil man nicht weiß, wieso er jz unerwartet reagiert...

    bb



  • aber trotzdem sollte man sich von anfang an dran gewöhnen, warnungen zu beachten.

    Ja, das hab ich vor.

    auch sollte man niemals fkt ohne nen return-wert implementieren

    Warum das? Ich hab recht viele Funktionen ohne return-Wert. Warum sollte ich die Funktion mit return-Wert machen, wenn klar ist, daß ich gar keinen brauche? Das macht es dann ja nur wieder schwerer, das Programm zu verstehen (also, was es macht).
    Daß mir der Fehler passiert ist, war, weil ich die Funktion von der get-Methode kopiert habe und das vergessen habe zu ändern.



  • war etwas unglücklich ausgedrückt : D
    war natürlich so gemeint:
    wenn die fkt etwas zurückgeben soll und du nur noch nicht den wert bzw die rechnung dazu hast, wie das zu errechnen ist, dann solltest du erst mal irgendetwas returnen lassen usw... sry ^^

    bb



  • unskilled schrieb:

    und wieso gibt er da ne warning und keinen fehler aus?

    Keine Ahnung. Standardkonform ist es trotzdem - der Standard verlangt lediglich "diagnostics", ob diese den Buildvorgang unterbrechen müssen, ist nicht spezifiziert. Außerdem beschränkt sich der Standard hier, wenn ich mich recht erinnere, ohnehin darauf, das Ergebnis als "undefiniert" zu betrachten.

    unskilled schrieb:

    allerdings nutzt er den fpu-stack auch nicht

    Freilich tut er - ich sehe da genau dasselbe FLD wie in meinem Code oben.

    unskilled schrieb:

    hat vll jmd nen link um mein (sehr) begrenztes asm-wissen zu erweitern? ^^

    http://www.google.de/search?q=fstp+fld

    susie schrieb:

    audacia schrieb:

    Das ist vielmehr ein Indiz, daß du mal auf Warnungen achten solltest. C++Builder emittiert in diesem Fall nicht zu Unrecht W8070.

    Ja, da hast Du recht (so hab ich es dann ja schließlich auch gefunden. Hatte halt noch diverse Testvariablen drin von früheren Debuggings, wo lauter Warnungen kamen, daß Variable xy nicht verwendet wird. Da ist das untergegangen. Hab den Code jetzt ein bißchen aufgeräumt, aber kann das nur step-by-step machen)
    Trotzdem, ein bißchen mehr Fehlermeldungen wären mir ja schon ganz lieb... Da tut man sich einfacher, wenn man nicht der Crack ist. Aber es ist, wie's ist...

    Du kannst das ändern - es gibt die Option, Warnungen als Fehler zu behandeln (Kommandozeilenoption -w! ). Die meisten der Warnungen von BCC sind berechtigt, daher ist der Einsatz von -w! empfehlenswert zur Förderung der Disziplin. Warnungen wie "xy wird deklariert/zugewiesen, aber nicht verwendet" (W8004/aus, W8057/par, W8080/use) kannst du deaktivieren ( #pragma warn -8057 oder #pragma warn -par bzw. Kommandozeilenoption -w-par ).



  • hmm... stimmt^^

    ty 🙂


Anmelden zum Antworten