Warum sollte man keine versteckten Anweisungen in logischen Ausdrücken ausführen lassen?



  • Nein, es wurde aus dem Bug ein zweifelhaftes "Feature" gemacht.


  • Mod

    Der echte Tim schrieb:

    Nein, es wurde aus dem Bug ein zweifelhaftes "Feature" gemacht.

    Quelle? Begründung?



  • Du glaubst nicht ernsthaft, dass signed overflow im Standard undefined ist damit Compilerbauer hier "optimieren" können?


  • Mod

    Der echte Tim schrieb:

    Du glaubst nicht ernsthaft, dass signed overflow im Standard undefined ist damit Compilerbauer hier "optimieren" können?

    Doch. Wenn es um 1-Komplement vs. 2-Komplement ginge, hätten sie implementation defined geschrieben. Durch undefined sind ziemlich gute Optimierungen möglich, vor allem was die Lauflänge von Schleifen angeht.



  • Wäre das tatsächlich der Grund, dann wäre es aber nur konsequent wenn unsigned overflow auch undefined wäre.

    Zumal man sich damals über derartige Optimierungen ziemlich sicher keine Gedanken gemacht hat. Denn dann hätte man Dinge wie restrict auch direkt eingeführt. Nein, damals hat man andere Sorgen gemacht, z.B. das (zum Glück mittlerweile entfernte) 31 Zeichen-Limit von Bezeichnern.



  • Was damals der Grund war es ursprünglich so zu machen ist die eine Frage.

    Was der Grund war weswegen es mit C++11 bzw. C++14 nicht geändert wurde ist eine andere Frage.

    Kann der selbe Grund sein, muss aber nicht.



  • NineT4 schrieb:

    Sorry Es sollte so aussehen:
    ich habe "n" an Stelle von "m" geschrieben

    if (n > 100 && m++ > 100){
       //tue etwas
    }
    
    if(n > 100 && m+1 > 100){ 
        m++; 
        //tue etwas 
    }
    

    Das ist nicht das gleiche.

    if (n > 100 )
       m++
       if ( m > 100)
       {
          //tue etwas
       }
    }
    

    Das ist wie das erste Beispiel, aber ganz einfach lesbar.



  • - signed overflow war schon immer UB (im Gegensatz zur signed (integralen) promotion, die schon immer IB war)
    - unsigned overflow war schon immer defined (wrap around), was ich persönlich für den praktischen Gebrauch für Unsinn halte, da hier Überläufe (stillschweigend und standardkonform!) verschleiert werden; ich möchte nicht wissen, wieviele Software in kritischen Bereichen im Umlauf ist, die dieses "Stillschweigen" aus Sorg- oder/und Ahnungslosigkeit "verwenden"
    - der Standard macht (naturgemäß) keine Vorgaben für Implementierungsvarianten geschweige denn Optimierungen
    - der Standard sieht aber sehr wohl prinzipielle Möglichkeiten vor, um solche fragilen Konstrukte sichtbar zu machen, er spricht z.B. von "the result is implementation-defined or an implementation-defined signal is raised" und bei UB spricht er sogar explizit davon, dass eine Implementierung (also ein Compiler) eine UB in eine constraint-violation umwandeln darf, die dann wiederum standardgemäß auch ein "signal" in irgendeiner Form von sich geben muss



  • lesenkönnen schrieb:

    if (n > 100 )
       m++
       if ( m > 100)
       {
          //tue etwas
       }
    }
    

    Das ist wie das erste Beispiel, aber ganz einfach lesbar.

    Mal abgesehen davon dass ein ";" fehlt...

    Nein, ist nicht "wie das erste Beispiel".
    Das Thema war aber eigentlich schon durch.



  • hustbaer schrieb:

    lesenkönnen schrieb:

    if (n > 100 )
       m++
       if ( m > 100)
       {
          //tue etwas
       }
    }
    

    Das ist wie das erste Beispiel, aber ganz einfach lesbar.

    Mal abgesehen davon dass ein ";" fehlt...

    Nein, ist nicht "wie das erste Beispiel".
    Das Thema war aber eigentlich schon durch.

    Und eine { fehlt auch.
    Aber

    #include <iostream>
        using namespace std;
    
        int main() {
        	int n = 180;
        	int m = 80;
        	if (n > 100 && m++ > 100){
           		//tue etwas
        	}
        	std::cout << "n: " << n << " m: " << m;
        	// your code goes here
        	return 0;
        }
    

    n: 180 m: 81

    #include <iostream>
        using namespace std;
    
        int main() {
        	int n = 180;
        	int m = 80;
        	if(n > 100 && m+1 > 100){
        	   m++;
            	//tue etwas
        	}
        	std::cout << "n: " << n << " m: " << m;
        	// your code goes here
        	return 0;
        }
    

    n: 180 m: 80

    #include <iostream>
        using namespace std;
    
        int main() {
        	int n = 180;
        	int m = 80;
        	if (n > 100 ) {
           		m++;
           		if ( m > 100)
           		{
              		//tue etwas
           		}
        	}
        	std::cout << "n: " << n << " m: " << m;
        	// your code goes here
        	return 0;
        }
    

    n: 180 m: 81

    Der Compiler macht doch aus jedem && wieder ein geschachteltes if.
    Zeigt ein Beispiel wo bei 1 und 3 nicht das gleiche raus kommt.



  • n = 101
    m = 100
    Wird "tue etwas" ausgeführt oder nicht?
    Im Original nicht.
    In deiner Variante schon.

    Hatten wir aber wie gesagt alles schon durch.
    https://www.c-plusplus.net/forum/p2478891#2478891



  • Igitt, wer hat denn so einen Bug in die Sprache eingebaut? Irgendwas links und rechts vom Vergleichsoperator nach dem Vergleich auszuführen ist doch total kontraintuitiv.



  • Das hat doch mit dem Vergleich nix zu tun.

    Ist halt die Semantik von n++ . Post increment halt.
    Auch ganz ohne if:

    int x = 100;
    printf("%d\n", x++); // Schreibt 100 raus
    printf("%d\n", x);   // Schreibt 101 raus
    


  • Gibt es ein Beispiel wo man Post increment sinnvoll braucht?



  • Brauchen ist relativ.
    Unbedingt brauchen tut man grundsätzlich nie mehr als was eben nötig ist um eine Sprache Turing-complete zu machen. (Manchmal sogar weniger, aber eben nie mehr.)

    Viele Dinge die darüber hinausgehen sind aber praktisch.

    Verwendet wird post-increment oft in Schleifen für Zeiger, Iteratoren oder Indizes.

    Ich persönlich verwende post-increment sehr sparsam. Bzw. meist nur mit eingebauten Typen ( int , ...) und wenn ich den Wert des post-increment Ausdrucks gar nicht verwende.
    Wie halt in der "klassischen for Schleife" for (int i = 0; i < something; i++)

    Beispiel das ohne post-increment wirklich deutlich hässlicher wäre fällt mir jetzt auf die Schnelle keines ein.


  • Mod

    hustbaer schrieb:

    Beispiel das ohne post-increment wirklich deutlich hässlicher wäre fällt mir jetzt auf die Schnelle keines ein.

    Wenn man kurzen Code schön findet, dann sind die Stringverarbeitungsfunktionen aus der C-Standardbibliothek gute Anwendungsgebiete für Postinkrement. Da kann man ein paar schicke Ein- und Zweizeiler schreiben, wo man sonst ein bisschen mehr Code bräuchte. Beispielsweise ist ein (naives) strcpy schreibbar als

    while(*dest++ = *src++);
    

    Das fällt alles in die Kategorie "Schleifen für Zeiger, Iteratoren oder Indizes".



  • Genau.
    Muss man aber nicht schön finden.
    Und "sinvoll brauchen" ist halt eben ne sehr subjektive Sache.

    EDIT: Wobei...
    Wenn man das Beispiel (abgesehen von der Schleife) etwas "umschreibt" zu...

    dest.WriteAndMoveToNext(src.ReadAndMoveToNext());
    

    ...sieht man dass die darin verwendeten Konstrukte - "WriteAndMoveToNext" und "ReadAndMoveToNext" - gar nicht so komisch sind.
    Im Gegenteil, sie sind sogar so "üblich", dass das "AndMoveToNext" im Namen oft weggelassen wird. z.B. bei typsichen File-IO Klassen.


Anmelden zum Antworten