Go Down

Topic: Code funktioniert nur manchmal (Read 4894 times) previous topic - next topic

Serenifly

Ich habe ja gesagt dass ein paar spezielle Anwendung gibt wo es seine Berechtigung hat. Aber hier wird es klar als unnötige Krücke verwendet.

combie

Ja,,,,,
Hier wird das Goto, etwas suboptimal, als Schleifenersatz, genutzt.

Wobei:
Das ist eigentlich genau die Stelle, ziemlich auf den Punkt getroffen, wo man Nebenläufigkeit brauchen können würde. Zumindest würde ich so denken.
Und damit ist (computed) Goto dann wieder voll im Rennen.

Viele Möglichkeiten hat man an der Stelle nicht, wenn man einen Automaten bauen will/muss.

1. irgendwas mit Enum Switch usw.
2. Functionpointer
3. Ein geschachteltes if else Gewirre
4. oder eben Goto


Man nimmt eben das, was schöner und praktischer ist.
!Ein Hoch auf Übersichtlichkeit und Wartungsfreundlichkeit!
Es ist auch eine Geschmacksfrage.
Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

michael_x

Quote
Aber wie immer:
> Wer einmal kapiert hat, wie ein Hammer funktioniert,
> für den sieht jedes Problem, wie ein Nagel aus.
Mal ganz ehrlich, ist hier nicht jedes Problem ideal für einen endlichen Automaten (Nachtwächter) ?

Eine Variante des goto ist übrigens das return; mitten im Code, mit dem man einfach an den Anfang von loop zurückspringt. Das wird eher toleriert und nur von echten Puristen wie ein goto ausgebellt.

combie

Quote
Mal ganz ehrlich, ist hier nicht jedes Problem ideal für einen endlichen Automaten (Nachtwächter) ?
Meiner Ansicht nach, sind die meisten, wenn nicht sogar alle, funktionierenden Arduino Programme endliche Automaten.
Und dabei ist es völlig egal, ob der Ersteller das wollte, oder nicht.

Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Doc_Arduino

Hallo,

>95% sind Zustandsautomaten würde ich behaupten.

Nur goto halte ich hier für völlig fehl am Platz. Schon weil sich die Lesbarkeit in Größenordnungen verschlechtert. Ein sauberes switch-case mit klaren enum Namen und gut ist. Dann ist der Code auch Jahre später einfach wartbar.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
Schon weil sich die Lesbarkeit in Größenordnungen verschlechtert.
Goto verschlechtert die Lesbarkeit?
Wie macht es das?


Das sehe ich nicht so.


Mit jedem Sprachmittel kann man Mist bauen, ohne Zweifel!
Aber das ist doch dann nicht die Schuld des Sprachmittels...

Und wenn ich mal so ehrlich sein darf:
Hier im Forum habe ich schon viel mehr hässliche Switch/Case Konstrukte gesehen, als Goto Einsätze.

Ganz nebenbei:
Bei größeren Konstrukten bietet das Goto gar einen Vorteil in Sachen Codegröße und Performance.
Bei kleinen Konstrukten wird  Switch/Case weitestgehend optimiert. Aber ab einer bestimmten Größe ist Schluss damit.

Das soll alles keine Werbung für den sinnfreien Goto Einsatz sein!
Sondern nur mein Beitrag gegen Dogmatismus.
Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Doc_Arduino

#36
Mar 10, 2018, 01:06 am Last Edit: Mar 10, 2018, 01:07 am by Doc_Arduino
Hallo,

wenn man switch case richtig macht, indem sich die enum Zustandsvariable nur innerhhalb switch-case verändert, dann ist das in Sachen Übersichtlichkeit nicht zu überbieten. Man kann ordentlich lesbare Zustandsnamen verwenden und ordentliche Funktionsnamen die dann aufgerufen werden. Das hilft die Funktionsweise wesentlich schneller zu überblicken.

Mit goto muss man erst das Label im gesamten Code suchen um zu wissen wo es weitergeht und was dort weiter geht.
Ich hätte gern ein konkretes Bsp. gewusst wo goto sinnvoll ist. Ich kann es mir derzeit nicht vorstellen.

Performance, da lese ich leider gegenteiliges, Abschnitt unten.
http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/008_c_kontrollstrukturen_012.htm
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Serenifly

Ich hätte gern ein konkretes Bsp. gewusst wo goto sinnvoll ist. Ich kann es mir derzeit nicht vorstellen.
Fehlerbehandlung und Resourcenfreigabe am Ende einer Funktion:
https://blog.regehr.org/archives/894

Wird z.B. im Linux Kernel sehr oft verwendet


combie

Performance, da lese ich leider gegenteiliges, Abschnitt unten.
http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/008_c_kontrollstrukturen_012.htm
Es tut mir leid, das sagen zu müssen:

Erstens:
Das ist ein C Buch, keine C++
OK, das hat wenig Auswirkungen an der Stelle... aber computed Goto kann altes C nicht.

Zweitens:
Das mit der Performance ist in dem Buch gelogen. Oder, zumindest nicht belegt. Du darfst diese Unwahrheit glauben. Aber weitererzählen, tue es bitte nicht. Denn sonst bezichtige ich dich der bewussten Lüge. Des bewussten weitererzählens dieser Unwahrheit .

Ok ok, vielleicht ist es ja keine bewusste Lüge von dem Autor, sondern nur ein Irrtum. Aber eigentlich gehören auch Irrtümer aus Dogmatismus auf den Haufen der Geschichte. Irrtümer und Lügen unterscheiden sich nur durch die dahinter stehende Absicht. Die Folgen sind nahezu identisch.

Drittens:
Das sich der Autor vom Dogmatismus gefangen fühlt hört man schon an dem Satz:
> Ich habe mir lange überlegt, ob ich Goto überhaupt in diesem Buch erwähnen soll, ....

Ein Fachbuchautor, welcher wegen solcher Gedanken mit sich hadert, ist an der falschen Stelle unterwegs. Unterdrückung und Zensur von Sprachmitteln in Sprachfachbüchern, ist so ziemlich das schlimmste, was man lernenden antun kann. Meiner Meinung nach.


---

Mache dir doch bitte bewusst, dass dieser anti Goto Dogmatismus aus einer Zeit stammt, als Subroutinen und Funktionen noch ein Fremdwort waren. Oder gerade eingeführt wurden. Der  anti Goto Dogmatismus stammt nicht aus C, oder gar aus C++, sondern ist ein Basic stämmiger  anti Goto Dogmatismus.
Goto war eine unabwendbare, absolute Notwendigkeit, alter Basic Dialekte.
Das hat mit uns hier doch gar nichts zu tun

Vergleichbares Argument:
Schokolade ist für Menschen giftig, weil ein Hund an einer Tafel Zartbitter stirbt, sterben kann.
Das mit dem Hund ist richtig. Aber die Übertragung auf den Menschen ist falsch. Denn, anderer Stoffwechsel.
Ein Informaltionsübertragungsfehler im Kopf.


Liebster Doc_Arduino, wärest du nicht selber diesem Dogma unreflektiert erlegen, dann würdest du das Performance Argument selber prüfen. Dass du nicht mal auf die Idee kommst, belegt deine Gläubigkeit.

---

Weiterhin:
Ja, mit Goto kann man Mist bauen.
Aber ein verantwortungsvoller Umgang damit ist möglich.
Das gilt für jedes Sprachmittel.
Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Doc_Arduino

Hallo,

das gezeigte Bsp. von Serenifly macht Sinn, sehe ich ein, in dem Fall kürzerer und besser lesbarer Code mit goto.

Ich verweigere mich nicht grundsätzlich Neuen, ich habe nur immer erstmal eine klare Meinung zu einem Thema. Kennt ihr ja.  :)   Wenn dann irgend jemand um die Ecke kommt und was anderes behauptet und ich verstehe es nicht oder kann es erstmal nicht nachvollziehen, dann frage ich nach und bohre nach. Genau das kann manchmal unbequem sein. Manchmal filtert das Unwissende von Wissenden heraus.  :)  Auch ich bin in der Lage meine Meinung zu ändern, man glaubt es kaum, nur ändere ich diese nicht auf Grund von dahin gewurfenen weiteren Behauptungen. Ansonsten fördert es oder sollte es das tiefere Verständnis fördern um das um was es geht. Gleichzeitig werden die Erklärungen immer besser und verständlicher.

ruhiges WE euch allen ...


Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Serenifly

#40
Mar 10, 2018, 03:34 pm Last Edit: Mar 10, 2018, 03:37 pm by Serenifly
Hier ist ein guter Artikel zur Performance von computed goto und wieso switch langsamer ist:
https://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables

Das ist aber auch ein spezieller Fall. computed goto ist nicht das gleiche wie ein normales goto. Hier braucht man die extra Geschwindigkeit nicht (außerdem gibt eine keine branch prediction die etwas beschleunigen könnte). Und man sollte verstehen was man macht und wieso.

combie

#41
Mar 10, 2018, 07:18 pm Last Edit: Mar 10, 2018, 07:41 pm by combie
Quote
Und man sollte verstehen was man macht und wieso.
Eigentlich soll Computed Goto Distanzen berechnen können.
Damit relative Gotos ermöglichen.
Das gilt für unseren GCC, noch als broken.(soweit mir bekannt)

Also eine Warnung:
Computed Gotos verwenden, ok.
Aber bitte keine Rechenoperationen auf den Lable Adressen ausführen und dann anspringen.
Das kann ins Auge gehen.

//----

Übrigens, eine Suche über meinen SketchOrdner, inklusive Libraries und Hardwaredefinitionen, führte über 1300 Gotos ans Licht.
Auch, oder eher gerade, in namhaften Libraries.

//----

Du möchtest ja Beispiele sehen......
Hier ein Doppelblinker Beispiel, aus meiner Wühlkiste, für einen kleinen endlichen Automaten mit Goto:
Code: [Select]

const byte taster     = 2;

class Blinker
{
  protected:
  const byte ledPin;
  const unsigned long hellPhase;
  const unsigned long dunkelPhase;
  unsigned long zeitMerker = 0;
  void *sprungZiel = 0; // zustandsmerker

  public:
  Blinker(const byte ledPin,const unsigned long hellPhase,const unsigned long dunkelPhase): ledPin(ledPin),hellPhase(hellPhase),dunkelPhase(dunkelPhase){}

  void run(const bool blinkAnforderung)
  {
    if(!sprungZiel) sprungZiel = &&Start;
    goto *sprungZiel;

    Start:
      if(!blinkAnforderung) return;
      digitalWrite(ledPin,HIGH);
      sprungZiel = &&HellPhase;
      zeitMerker = millis();
   
    HellPhase:
      if(millis()-zeitMerker<hellPhase) return;
      digitalWrite(ledPin,LOW);
      sprungZiel = &&DunkelPhase;
      zeitMerker = millis();
 
    DunkelPhase:
      if(millis()-zeitMerker<dunkelPhase) return;
      sprungZiel = 0;
  }
 
  void init()
  {
    pinMode(ledPin,OUTPUT);
  }
};


Blinker blinkGruppe[] = { // {pin,hellzeit,dunkelzeit}
                          {13,100, 500},
                          {12,500,1000},
                        };




void setup()
{
  pinMode(taster,INPUT_PULLUP);
  for(Blinker &blinker:blinkGruppe) blinker.init();
}

void loop()
{
  bool blinkAnforderung = !digitalRead(taster);
  for(Blinker &blinker:blinkGruppe) blinker.run(blinkAnforderung);
}


Ob das jetzt ein gutes Beispiel ist, kann ich nicht sagen. Aber dennoch ist es mit Goto und dabei recht übersichtlich.

Bei der Verwendung von enum Switch/case würde der Compiler versuchen eine Sprungtabelle anzulegen.
Dann würden sich erstmal keine Performance Vorteile, für Goto, ergeben.

Aber:
Wenn die case nicht fortlaufend definiert sind, oder die Anzahl ein gewisses Maß überschreitet, dann generiert der Compiler ein Konstrukt, welches einer langen if Kette entspricht. Dann dauert es eben diese Anzahl Vergleiche, bis der betreffende Case erkannt und ausgeführt wird. Natürlich, je weiter ein Fall hinten steht, desto länger dauert es dann bis zur Ausführung.




Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Whandall

Fehlerbehandlung und Resourcenfreigabe am Ende einer Funktion:
https://blog.regehr.org/archives/894

Wird z.B. im Linux Kernel sehr oft verwendet
Weil der Linux Kernel in C geschrieben ist.

C++ Programmierer benutzen zumindestens für die Resourcen bevorzugt Konstruktoren/Destruktoren.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

combie

Quote
C++ Programmierer
Richtige C++ Programmierer würden wohl Exceptions nutzen.

Aber das dürfen wir AVRler leider nicht.


Gefährlich, was Theorien aus Menschen machen können.
Schlimmer, was Menschen aus Theorien machen.

Whandall

Das würde die Fehlerbehandlung abdecken, was zumindestens auf den kleinen Arduinos nicht geht,
weil die einfach zu wenig Speicher haben.

Auf einem ESP32 dürften Exceptions durchaus benutzbar sein.

Auf Microcontrollern ist OOP auf alle Fälle nützlich und sinnvoll einsetzbar.

Nur goto halte ich hier für völlig fehl am Platz. Schon weil sich die Lesbarkeit in Größenordnungen verschlechtert.
Ein sauberes switch-case mit klaren enum Namen und gut ist. Dann ist der Code auch Jahre später einfach wartbar.
Dem kann ich nur zustimmen.  :D

Bei geeigneten (zusammenhängenden) Auswahlwerten erzeugt der Kompiler ein computed goto.
Das ist bei enums überwiegend der Fall.
Weiterhin kann der Kopiler feststellen, wenn man einen der Fälle vergessen hat.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Go Up