switch-case Problematik



  • Bin mir nicht sicher, wie der switch-case Mechanismus genau arbeitet.

    Hierzu ein vereinfachter Algorithmus. In der ersten Version laufe ich einfach zum nächsten Label. Im zweiten Algorithmus habe ich den switch-case Block in eine Infinite-Loop gepackt und springe immer wieder mit "continue" an den Anfang des switch-case Blocks. Damit kann ich sicher sein, dass der richtige case auch erreicht wird. Würde der Compiler (ich weiss es nicht) die Reihenfolge der Cases ändern, dann ist die erste Version unsicher.

    Erste Version

    switch (phase) {
      case 0:
        while (current_move < last_move) {
          move = (current_move++)->move;
          if (move_is_legal(move)) return move;
        }
        phase++;
        current_move = move_list;
        last_move = generate_captures(move_list);
        // hier laufe ich einfach zum nächsten Label
    
      case 1:
        while (current_move < last_move) {
          move = (current_move++)->move;
          if (move_is_legal(move)) return move;
        }
        phase++;
        current_move = move_list;
        last_move = generate_non_captures(move_list);
        // hier laufe ich einfach zum nächsten Label
    
      case 2:
        // more cases...
      }
    

    Zweite Version

    while (1) {
      switch (phase) {
      case 0:
        while (current_move < last_move) {
          move = (current_move++)->move;
          if (move_is_legal(move)) return move;
        }
        phase++;
        current_move = move_list;
        last_move = generate_captures(move_list);
        continue;  // Ist es notwendig wieder an den Anfang zu springen?
    
      case 1:
        while (current_move < last_move) {
          move = (current_move++)->move;
          if (move_is_legal(move)) return move;
        }
        phase++;
        current_move = move_list;
        last_move = generate_non_captures(move_list);
        continue;  // Ist es notwendig wieder an den Anfang zu springen?
    
      case 2:
        // more cases...
      }
    }
    

    Frage:
    Ist die zweite Version sicherer, da ich nach jedem case an den Anfang des switch Blockes springe?

    Gruss
    T.



  • Das ist das Durchfall prinzip. Der Code läuft einfach so weiter, bis er ein "break;" findet. Ein break beendet die Switch-Anweisung.

    Das ist übrigens keine "Problematik", sondern ein Sprachfeature.



  • Das ist mir schon klar. Nur kann es passieren, dass der Compiler die Reihenfolge meiner cases verändert?

    Wie ist das im Standard definiert?



  • Es kann passieren, dass die Reihenfolge geändert wird. Der Compiler stellt aber sicher, dass dein Code so ausgeführt wird, wie du es erwartest (mittels Sprunginstruktionen).

    Du kannst dich also ruhig darauf verlassen, dass alles so passiert wie du es erwartest.



  • Oft wird der case als 'if' missverstanden.

    Es wurde schon gesagt, ich will es dennoch nochmal betonen

    switch erzeugt einen Sprungbefehl:
    case ist das Sprungziel (label)

    Das führt ab ca. 3 cases zu besserer Performance als if / else if Konstrukte.
    Zudem finde ich den Code in solchen Fällen mit switch/case besser lesbar.

    Gruß Frank



  • Frank Erdorf schrieb:

    Das führt ab ca. 3 cases zu besserer Performance als if / else if Konstrukte.

    Falls die Fälle aufeinanderfolgende Zahlen sind.
    Auch nicht vergessen darf man das vorherige if(x<min || x>max) jump default;, das im switch verbaut ist.

    Frank Erdorf schrieb:

    Zudem finde ich den Code in solchen Fällen mit switch/case besser lesbar.

    Kommt drauf an. switch ist fast ausgestorben und hat den Malus des Ungewöhnlichen.



  • volkard schrieb:

    Kommt drauf an. switch ist fast ausgestorben und hat den Malus des Ungewöhnlichen.

    Wieso das denn? Willst du damit auf virtuelle/abstrakte Methoden hinweisen?



  • volkard schrieb:

    Frank Erdorf schrieb:

    Das führt ab ca. 3 cases zu besserer Performance als if / else if Konstrukte.

    Falls die Fälle aufeinanderfolgende Zahlen sind.

    Auch wenn das nicht der Fall ist, kann das durchaus performanter sein. Zumindest wenn die Zahlenabstände nicht zu groß sein sollten.



  • mazal schrieb:

    volkard schrieb:

    Kommt drauf an. switch ist fast ausgestorben und hat den Malus des Ungewöhnlichen.

    Wieso das denn? Willst du damit auf virtuelle/abstrakte Methoden hinweisen?

    Und an Funktionszeigertabellen und die ganze Entwicklung, daß immer mehr userkonfigurierbar wird und weniger hartverdrahtet.



  • volkard schrieb:

    Und an Funktionszeigertabellen und die ganze Entwicklung, daß immer mehr userkonfigurierbar wird und weniger hartverdrahtet.

    Mag vielleicht für den ganzen GUI- Klimbim gelten, in der Steuerungstechnik ist switch/case keinesfalls exotisch, sondern eher unverzichtbar, wenn der Code übersichtlich bleiben soll.

    Eine ganz andere Sache: Kann das sein, daß im Switch- Block break und continue ungleich behandelt werden? break beendet switch, soweit klar, aber continue bezieht sich nur auf eine umgebende Schleife, nicht auf den switch- Block? Wär' ja irgendwie inkonsistent ...



  • Nur kann es passieren, dass der Compiler die Reihenfolge meiner cases verändert?

    Wie kommst du ueberhaupt auf diese Idee?



  • pointercrash() schrieb:

    Eine ganz andere Sache: Kann das sein, daß im Switch- Block break und continue ungleich behandelt werden? break beendet switch, soweit klar, aber continue bezieht sich nur auf eine umgebende Schleife, nicht auf den switch- Block? Wär' ja irgendwie inkonsistent ...

    Da continue für switch gar keine Bedeutung hat, ist es doch genau so logisch.



  • volkard schrieb:

    pointercrash() schrieb:

    Eine ganz andere Sache: Kann das sein, daß im Switch- Block break und continue ungleich behandelt werden? break beendet switch, soweit klar, aber continue bezieht sich nur auf eine umgebende Schleife, nicht auf den switch- Block? Wär' ja irgendwie inkonsistent ...

    Da continue für switch gar keine Bedeutung hat, ist es doch genau so logisch.

    Du verwechselst Definition mit Logik und behauptest, weil es so definiert ist, ist es auch logisch. Das ist sophistische Selbstreferenz, aber kein Argument.

    Wer von anderen Sprachen ausgeht, wird nämlich auch erstmal das break unlogisch finden und des öfteren wohl auch mal vergessen ;). Könnte sich continue auf switch beziehen, würde der switch- Block einfach nochmal durchlaufen, was so nebenzu zu einer multikonditionalen Schleife führen würde.
    Oder andersrum gefragt, worin liegt die Logik do/while/for mit beidem (break / continue) auszustatten, aber switch nicht?



  • Was sollte continue bei switch denn tun?



  • pointercrash() schrieb:

    Wer von anderen Sprachen ausgeht, wird nämlich auch erstmal das break unlogisch finden und des öfteren wohl auch mal vergessen ;).

    Dann macht er eben was falsch. Insbesondere hält er C für eine Sprache wie Java oder Basic.
    Das ist keine gute Sichtweise. C soll man sehen als recht angenehmen Makroassembler, und dann begreift man die Sprachmittel auch.

    Du verwechselst Definition mit Logik und behauptest, weil es so definiert ist, ist es auch logisch. Das ist sophistische Selbstreferenz, aber kein Argument.

    Nö, ich bezog mich darauf, daß continue bei switch keinen Sinn ergibt. Und wegen Sinnlosigkeit der einen Alternative ist die andere die logische.



  • volkard schrieb:

    Nö, ich bezog mich darauf, daß continue bei switch keinen Sinn ergibt. Und wegen Sinnlosigkeit der einen Alternative ist die andere die logische.

    Ist ja nicht sinnlos, wenn mit continue einfach zur Auswertung des switch- Arguments zurückgesprungen würde. Das wäre völlig analog zur Behandlung von continue in Schleifen.
    Im Gegenteil, es nicht so zu machen, bedeutet den größeren logischen Bruch.



  • pointercrash() schrieb:

    volkard schrieb:

    Nö, ich bezog mich darauf, daß continue bei switch keinen Sinn ergibt. Und wegen Sinnlosigkeit der einen Alternative ist die andere die logische.

    Ist ja nicht sinnlos, wenn mit continue einfach zur Auswertung des switch- Arguments zurückgesprungen würde. Das wäre völlig analog zur Behandlung von continue in Schleifen.
    Im Gegenteil, es nicht so zu machen, bedeutet den größeren logischen Bruch.

    Dann wäre switch ja nicht mehr eine Sprungtabelle, sondern eine Schleife.
    Tut mir leid, deiner Logik folge ich nicht.
    Man hätte statt "break" sich ein anderes Schlüsselwort einfallen lassen können, vielleicht "endcase", aber das ist eine andere Geschichte.



  • volkard schrieb:

    Dann wäre switch ja nicht mehr eine Sprungtabelle, sondern eine Schleife.

    Und das wäre entsetzlich?

    volkard schrieb:

    Tut mir leid, deiner Logik folge ich nicht.

    Das ist nicht "meine Logik", sondern die allgemeine Logik, Analogien bei Programmiersprachen weitestmöglich beizubehalten. Wenn wir ein switch mitm while außenrum haben, bricht man mit einem continue beide Strukturen, mit einem break nur das innere switch. Andererseits braucht man zwei breaks, um die Schleife endgültig abzubrechen. Das soll logisch sein?

    volkard schrieb:

    Man hätte statt "break" sich ein anderes Schlüsselwort einfallen lassen können, vielleicht "endcase", aber das ist eine andere Geschichte.

    Wenn ich keine Analogien provozieren mag, die nicht gegeben sind, wäre ein anderes Keyword ein Muß gewesen. Logischer wäre, dem switch sein continue zu geben. 😃



  • Ich bin dankbar, daß Du keine "logische" Sprache entwirfst.



  • pointercrash() schrieb:

    Ist ja nicht sinnlos, wenn mit continue einfach zur Auswertung des switch- Arguments zurückgesprungen würde. Das wäre völlig analog zur Behandlung von continue in Schleifen.
    Im Gegenteil, es nicht so zu machen, bedeutet den größeren logischen Bruch.

    continue ist für Schleifenkonstukte definiert, switch ist keines, daher sollte continue keine Auswirkungen auf switches ohne umrahmende Schleifen haben, also NoOp.
    Philosophieren darüber ist aber sicher erlaubt 🙂



  • Ich stelle mir das schon vor:

    switch (x)
    {
     case 1:
      break; // Beendet Case-Zweig
      break; // Verlässt Switch-Schleife
    
     case 2:
      continue; // Beginnt von vorne (Start der Switch-Schleife)
      break; // Beendet Case-Zweig
    
     default:
      break; // Beendet Case-Zweig
      break; // Verlässt Switch-Schleife
    }
    

    🤡


Anmelden zum Antworten