Statemachine, Funktionszeiger oder Variable

Gast #892020
Lesenswert?

> 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.
Gast #892032
Lesenswert?

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.
Gast #892086
Lesenswert?

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.
#899496
Lesenswert?

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...
Gast #900056
Lesenswert?

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.
Gast #900113
Lesenswert?

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
#900185
Lesenswert?

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.
Gast #902322
Lesenswert?

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.
Gast #902334
Lesenswert?

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.
Gast #902615
Lesenswert?

> 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
;-)
Gast #905954
Lesenswert?

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.
Moderator Persönliche Seite #906022
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren