Forum: Mikrocontroller und Digitale Elektronik C: Instanzierung von Funktionen


von Third E. (third-eye)


Lesenswert?

Hallo,

bei mir kommt es öfter mal vor, dass ich einen Zustandsautomaten als 
Funktion erstelle. In der Funktion gibt es dann die 
static-Zustandsvariable (Enumeration) "zustand".

Vor kurzem hatte ich die Herausforderung, dass ich auf einem AVR mehrere 
Duplikate des Automaten quasiparallel laufen lassen musste.
Ich habe das dann so gelöst, dass ich Eingabedaten und Ausgabedaten als 
Parameter bzw. als Pointer übergeben habe. Außerdem habe ich außerhalb 
der Funktion "zustand" als Array erstellt und ebenfalls das jeweilige 
Arrayelement als Zeiger übergeben.

Das ganze hat recht gut funktioniert, hatte aber den Nachteil, dass ich 
zusätzlich mehrere Variablen auch von außen als Zeiger übergeben musste, 
die ich vor der Instanzierung als static-Variable in der Funktion hatte.

Gut, man könnte diese Variablen als Struct zusammenfassen, aber so schön 
ist das auch nicht.

Oder da fällt mir gerade ein, man könnte ja in der Funktion diese 
Static-Variablen auch als Array definieren.

Wie macht Ihr sowas?
Vielleicht gibt es komfortablere Lösungen dafür?

Danke.
Third-Eye

: Bearbeitet durch User
von Sven P. (Gast)


Lesenswert?

Third Eye schrieb:
> Wie macht Ihr sowas?
Den Automaten eintrittsinvariant schreiben und die Zustandsvariable in 
einer Struktur sammeln und an den Automaten durchreichen. Etwa per 
Zeiger.


> Vielleicht gibt es komfortablere Lösungen dafür?
C++, mit allen Vor- und Nachteilen z.B.

von Mark B. (markbrandis)


Lesenswert?

Wenn Du "mehrere Instanzen einer Funktion" haben willst, nimm C++ ;-)

von Karl H. (kbuchegg)


Lesenswert?

Third Eye schrieb:


> Gut, man könnte diese Variablen als Struct zusammenfassen, aber so schön
> ist das auch nicht.

Doch. Genau das ist die Technik.

> Oder da fällt mir gerade ein, man könnte ja in der Funktion diese
> Static-Variablen auch als Array definieren.

Nicht 'in der Funktion'.
Ausserhalb.

Du hast 'Objekte'.

Jedes Objekt besteht aus einer Sammlung aller für diesen Objekttyp 
relevanten Variablen. In C ist das eben ein struct.
Und du hast Methoden, die auf den Objekten arbeiten.
In C ist das eben eine Funktion, der du eine struct mitgibst (einen 
Pointer auf die struct), so dass die Funktion alles hat.

Im Grunde ist das schon der erste Schritt in Richtung 
objektorientierung.

> Vielleicht gibt es komfortablere Lösungen dafür?

Das ist schon das beste was du kriegen kannst
1
struct MachineState
2
{
3
  uint8_t State;
4
  ....
5
};
6
7
struct MachineState Machines[5] = { .... };
8
9
#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
10
11
void handleMachine( struct MachineState* pMachine )
12
{
13
  switch( pMachine->State )
14
  {
15
    case ....
16
  }
17
}
18
19
void work()
20
{
21
  while( 1 )
22
  {
23
    for( uint8_t i = 0; i < ARRAY_SIZE(Machines); i++ )
24
      handleMachine( &Machines[i] );
25
  }
26
}

Hat man mehrere unterschiedliche State-Maschinen, die dann auch 
unterschiedliche Bearbeitungsfunktionen für die Stati brauchen, dann 
gibt man eben noch einen Funktionspointer mit in die struct hinein. Das 
wäre dann das Äquivalent dazu, was in C++ zb eine virtuelle Funktion 
wäre.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Gibt es wirklich keinen C++ Compiler für deine Plattform, so dass man 
das 'zu Fuss' erledigen muss?

von Peter II (Gast)


Lesenswert?

PittyJ schrieb:
> Gibt es wirklich keinen C++ Compiler für deine Plattform, so dass man
> das 'zu Fuss' erledigen muss?

was ist schlimm daran? Der ganze Linux-Kernel ist in C geschrieben.

von Karl H. (kbuchegg)


Lesenswert?

PittyJ schrieb:
> Gibt es wirklich keinen C++ Compiler für deine Plattform, so dass man
> das 'zu Fuss' erledigen muss?

So schlimm ist das auch wieder nicht.
Ob du das so wie oben in der C Version schreibst, oder so
1
class MachineState
2
{
3
public:
4
  ...
5
  void handleMachine();
6
7
private:
8
  uint8_t State;
9
};
10
11
void MachineState::handleMachine()
12
{
13
  switch( State )
14
  {
15
    case ....
16
  }
17
};
18
19
class MachineState Machines[5];
20
21
#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
22
23
void work()
24
{
25
  while( 1 )
26
  {
27
    for( uint8_t i = 0; i < ARRAY_SIZE(Machines); i++ )
28
      Machines[i].handleMachine();
29
  }
30
}

ist erst mal kein so großer Unterschied.
Wenn man von der Klasse ableiten kann, sieht die Sache ein wenig anders 
aus, das ist aber bei so State Maschines grob geschätzt eher selten der 
Fall.

von Mark B. (markbrandis)


Lesenswert?

Peter II schrieb:
> was ist schlimm daran? Der ganze Linux-Kernel ist in C geschrieben.

Warum Auto fahren? Mit der Pferdekutsche kommt man doch auch ans Ziel. 
;-)

von Stefan (Gast)


Lesenswert?

Letztendlich macht C++ es ja intern ganz genau so. Jede Objekt-Methode 
wird einem (im Quelltext nicht sichtbaren) Zeiger auf die Daten des 
Objektes aufgerufen.

Die Funktion MeinGeld.vermehre(100) hat also in Wirklichkeit zwei 
Parameter, etwa so: vermehre(MeinGeld,100)

Man kann das erkennen, wenn man sich den erzeugten Assembler-Code 
anschaut.

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
Noch kein Account? Hier anmelden.