Was findet ihr "schöner", eine Statemachine die mit hilfe von einen Funktionszeiger auf die "states" zeigt oder ein switch/case oder if/else mit hilfe einer Variable?
> eine Statemachine die mit hilfe von einen Funktionszeiger auf die > "states" zeigt Das habe ich nicht verstanden. Ein Funktionszeiger zeigt auf eine Funktion. Ist dann der Zustand ebenfalls eine Funktion? Wie soll das gehen? Bei meinen Statemachines ist der Zustand meist eine Enum-Variable. Ihr Inhalt wird in einer switsch/case-Anweisung abgefragt, wenn es mehr als zwei Zustände gibt, sonst in einem if/else.
ok
1 | void (*Funktion)(void); |
2 | |
3 | void machewas1() |
4 | {
|
5 | Funktion = machewas2; |
6 | }
|
7 | void machewas2() |
8 | {
|
9 | Funktion = machewas3; |
10 | }
|
11 | void machewas3() |
12 | {
|
13 | Funktion = machewas1; |
14 | }
|
15 | |
16 | void machs() |
17 | {
|
18 | Funktion(); |
19 | }
|
Das geht natürlich auch mit Eingangsparametern. zum Beispiel ein Byte was vom UART kommt.
Jetzt ist klar, wie das gemeint war. Ja, so geht das natürlich auch. Ich würde sagen, welcher Variante man den Vorzug gibt, ist Geschmackssache. Bei der switch/case-Variante können einfache Aktionen direkt in die case-Abschnitte geschrieben und dadurch einige Funktionsaufrufe eingespart werden. Außerdem kann die Zustandsvariable zu Debugzwecken leichter ausgegeben werden, da es sich dabei um einen Integerwert handelt. Die Funktionspointervariante dürfte auf vielen Architekturen etwas schneller sein, insbesondere dann, wenn die einzelnen Aktionen sowieso schon als Funktionen vorliegen.
Ich würde im Normalfall die Variante mit der Statevariablen und dem Switch/Case bevorzugen, weil sie, wie @yalu auch schon sagte, leichter zu debuggen ist. Und das finde ich gerade bei Statemachines sehr wichtig - sie sind so schon schwierig genug. Und der Inhalt von Funktionszeigern ist eine Adresse und beim debuggen absolut schwierig zu interpretieren. Und, ich will mir das Leben ja leicht machen...
Das mit dem Debuggen kann schon ein Argument sein. Allerdings, falls die Statemaschine mit der Zeit wachsen soll, finde ich die Variante mit dem Funktionszeiger sehr elegant. Die Grundfunktion (dort wo normalerweise der State ausgewertet wird) bleibt immer gleich, alle State(funktionen) bleiben gleich, neue hinzufügen und gut ist. Eine Statemaschine mit Switch die sich über mehrere Seiten hinzieht ist für mich der Horror.
Vor allem bei geschachtelten Zuständen ist eine Kombination aus beidem auch gar nicht so schlecht. Die Hauptzustände über Funktionszeiger, in den Funktionen dann kleine switch/case-Maschinchen, falls erforderlich. Oliver
StinkyWinky wrote: > Das mit dem Debuggen kann schon ein Argument sein. Allerdings, falls die > Statemaschine mit der Zeit wachsen soll, finde ich die Variante mit dem > Funktionszeiger sehr elegant. > Die Grundfunktion (dort wo normalerweise der State ausgewertet wird) > bleibt immer gleich, alle State(funktionen) bleiben gleich, neue > hinzufügen und gut ist. Wenn man für die Variable ein enum verwendt und im switch/case-Ausdruck auch die Namen der enums verwendet, lässt sich eine Statemachine auch so relativ einfach erweitern: Enum erweitern, case-Bedingung einfügen und gut ist.
Da hast Du absolut recht. Wenn das Konzept der SM gut gewählt ist, spielt es keine Rolle, ob mit Funktionspointer oder Switch/Enum. Allerdings habe ich schon mehrere Implementationen mit Switch/Enum gesehen, welche ziemlich Spaghetti-artig waren. Mit den Funktionen wird man zur Modularität gezwungen, was ich als Vorteil erachte.
Wo wendet ihr eigentlich Funktionszeiger an? Wenn man objektbasierend in C programmiert oder die klassische Sortierfunktion. Die Beispiele kenne ich. Ich meine, bei der alltäglichen Programmierung in C.
Die Variante mit den Funktionszeigern kannte ich gar nicht, wäre aber ab sofort mein Favorit :) ... zumindest für die Fälle, wo sich das anwenden lässt.
>Wo wendet ihr eigentlich Funktionszeiger an?
Zwar nicht in C aber ich verwende die gerne für Event-Handling.
>Wo wendet ihr eigentlich Funktionszeiger an?
z.B. in einer statemachine :-)
Oliver
Habe ich (nebst SM) schon eingesetzt um zwischen verschiedenen Regelalgorithmen umschalten zu können. Auch für Callbacks schon benützt.
Ich glaube ein Callback-Funktion ist das häufigste Anwendungsbeispiel ;) http://de.wikipedia.org/wiki/R%C3%BCckruffunktion
> Wo wendet ihr eigentlich Funktionszeiger an? > ... > Ich meine, bei der alltäglichen Programmierung in C. Etwas Alltägliches sind Funktionszeiger in C nicht. Aber ab und zu sind die Dinger schon ganz praktisch. Beispiele: - Kommandozeileninterpreter: Eine Tabelle enthält für jedes Kommando den Namen, einen Zeiger auf die Funktion, die das Kommando ausführt und ggf. noch ein paar Zusatzinformationen. Man kann dann den Kommandonamen mittels einer Schleife (oder ggf. auch mit einem effizienteren Suchalgorithmus) suchen lassen und ruft anschließend die zugehörige Funktion über den Zeiger auf. Die Alternative wäre eine längere und nicht besonders schöne If-Elseif-Anweisung. So etwas Ähnliches wird hier (Datei evalf.cpp, Methode Eval::function) bei der Auswertung von arithmetischen Ausdrücken gemacht, um in eine größere Anzahl unterschiedlicher mathematischer Funktionen (sin, cos, tan usw.) zu verzweigen Beitrag "Re: Weis jemand, wie man mathematische Ausdrücke in C++ auswert" - Ich hatte einmal einen Minicompiler geschrieben, der als String vorliegende mathematische Funktionen (z.B. 3*x+sin(x)) direkt in optimierten Maschinencode umsetzt und diesen in ein Byte-Array schreibt. Über einen Zeiger auf dieses Array, der in einen Funktionszeiger gecastet wurde¹, konnte die kompilierte Funktion dann beliebig oft mit unterschiedlichen Argumenten für x aufgerufen werden (z.B., um die Funktion numerisch zu integrieren, Nullstellen zu suchen, Funktionsgraphen zu erstellen usw.). - Beim Multithreading wird der im Thread auszuführende Code ebenfalls üblicherweise als Funktionszeiger übergeben. So arg viel mehr Beispiele für die Verwendung von Funktionszeigern fallen mir aber gerade nicht ein. In anderen Programmiersprachen, insbesondere in Funktionalsprachen, ist die Umgang mit Funktionen wesentlich ungezwungener als in C. Es ist dort bspw. durchaus üblich, dass einer Funktion eine oder mehrere andere Funktionen als Funktionsargumente übergeben werden und der Funktionswert ebenfalls eine Funktion ist. ¹) Kinners, bitte nicht nachmachen! Heutzutage ist Casten zwischen Daten- und Funktionszeigern böse. Das dürfen nur noch Betriebssysteme ;-)
ok, hab es jetzt mit Funktionszeigern gemacht. Ist aber auch ein relativ lineare Statemachine, die einen Ablauf steuert. Ich finde beide Methoden haben ihre Berechtigung. Nur gefällt mir die mit den Funktionszeigern persönlich vom C-Code besser.
yalu wrote: > ¹) Kinners, bitte nicht nachmachen! Heutzutage ist Casten zwischen > Daten- und Funktionszeigern böse. Es geht schlicht und einfach auch nicht überall. Ein typisches Beispiel ist der AVR. Allerdings kann man einen generischen Funktionszeiger bauen und den in einen konkreten Zeiger casten, da alle Funktionszeiger ineinander umwandelbar sind. Außerdem könnte man natürlich noch einen Funktionszeiger alternativ zu einem Datenzeiger in eine union legen...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.