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



  • - 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