Zustandsmaschine in C

Waqar Aslam 12 Oktober 2023
  1. eine Übersicht über die Zustandsmaschine
  2. Verwendung von Funktionszeigern zur Erstellung einer Zustandsmaschine
  3. Verwenden Sie die Switch-Anweisung, um eine Zustandsmaschine zu erstellen
Zustandsmaschine in C

Dieser Artikel demonstriert die Implementierung des Zustandsautomaten in der Programmiersprache C.

eine Übersicht über die Zustandsmaschine

Die Verwendung einer Zustandsmaschine zur Implementierung von Code ist eine wertvolle Entwurfsstrategie zur Lösung komplexer technischer Probleme. Zustandsmaschinen nehmen das Gesamtdesign und teilen es in Stufen auf, die im Zustandsmaschinen-Jargon als Zustände bezeichnet werden.

Jeder Staat ist für die Erfüllung einer bestimmten Funktion verantwortlich. Auf der anderen Seite sind Ereignisse die Stimuli, die bewirken, dass die Zustandsmaschine zwischen Zuständen wechselt. Er wird auch als Übergang bezeichnet.

Wenn sie zum ersten Mal geschrieben werden, sind die meisten Systeme unkompliziert und gut organisiert, aber wenn neue Funktionen hinzugefügt werden, werden zusätzliche Flags und Variablen erstellt, um den Verlauf der Ereignisse zu verfolgen.

Dann werden if- und else-Anweisungen hinzugefügt, um die immer komplexer werdenden logischen Ausdrücke zu testen, die aus den vielen Variablen und Flags erstellt werden.

Dabei helfen die Zustandsmaschinen. Zustandsautomaten vereinfachen bei entsprechender Anwendung die an jedem Verzweigungspunkt geprüften Bedingungen und erleichtern das Umschalten zwischen verschiedenen Modi der Programmausführung.

Es stellt sich heraus, dass das Verhalten der meisten Echtzeitsysteme in eine relativ kleine Anzahl von sich nicht überschneidenden Blöcken (Zuständen) unterteilt werden kann.

Die Ereignisantworten innerhalb jedes Chunks hängen nur vom aktuellen Ereignis ab und nicht mehr von der Abfolge von Ereignissen, die in der Vergangenheit aufgetreten sind.

Verwendung von Funktionszeigern zur Erstellung einer Zustandsmaschine

Das Folgende ist ein Codebeispiel zum Erstellen einer Zustandsmaschine in C. Dieses spezifische Beispiel generiert zwei Zustands-Schalter zwischen ihnen zehnmal hin und her.

Dann zeigt es die Indexnummer und den Zustand an, der diesem Index entspricht.

#include <stdio.h>

struct state;
typedef void state_fn(struct state *);

struct state {
  state_fn *next;
  int i;
};

state_fn off_state, on_state;

void off_state(struct state *state) {
  printf("%s %i\n", __func__, ++state->i);
  state->next = on_state;
}

void on_state(struct state *state) {
  printf("%s %i\n", __func__, ++state->i);
  state->next = state->i < 10 ? off_state : 0;
}

int main(void) {
  struct state state = {off_state, 0};
  while (state.next) state.next(&state);
}

Ausgang:

off_state 1
on_state 2
off_state 3
on_state 4
off_state 5
on_state 6
off_state 7
on_state 8
off_state 9
on_state 10

Verwenden Sie die Switch-Anweisung, um eine Zustandsmaschine zu erstellen

Um einen soliden Start zu erreichen, sollten Sie die Menge der Zustände auflisten, in denen sich unser Programm befinden kann, und die Menge der Ereignisse, die es verarbeiten kann.

Dieses Programm kann sich in einem dieser drei Zustände befinden: START,, ITERATE, oder END.

enum states {
  START,
  ITERATE,
  END,
} state;

Es kann die Ereignisse START LOOPING, SHOW_MESSAGE und STOP LOOPING verarbeiten. Nach Erhalt des Ereignisses START LOOPING im START-Zustand geht unser Programm in den ITERATE-Zustand über.

Im ITERATE-Zustand zeigt es die Nachricht, wenn es das SHOW_MESSAGE-Ereignis empfängt. Schließlich geht es in den Zustand END über, nachdem es das Ereignis STOP LOOPING empfangen hat.

enum events {
  START_LOOPING,
  SHOW_MESSAGE,
  STOP_LOOPING,
};

Lassen Sie uns eine switch-Anweisung verwenden, die den aktuellen Zustand betrachtet und den entsprechenden Fall ausführt. Wir haben drei primäre Situationen, die als START,, ITERATE, und END bezeichnet werden.

Wenn innerhalb des START-Falls das empfangene Ereignis START LOOPING ist, ändert es den Status in ITERATE. Der Fall wird gebrochen, wenn das Ereignis nicht START LOOPING ist.

In ähnlicher Weise wird im ITERATE-Fall, wenn das empfangene Ereignis SHOW MESSAGE ist, die Nachricht angezeigt; andernfalls prüft es auf den Fall STOP LOOPING und ändert den Zustand auf END.

Wenn keines dieser Ereignisse empfangen wird, wird es unterbrochen und mit dem nächsten Fall fortgefahren. Schließlich bewirkt der Fall END, dass die Anweisung switch beendet wird und das Programm beendet wird.

void switchState(enum events event) {
  switch (state) {
    case START:
      switch (event) {
        case START_LOOPING:
          state = ITERATE;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case ITERATE:
      switch (event) {
        case SHOW_MESSAGE:
          printf("State Machine Ready!\n");
          break;
        case STOP_LOOPING:
          state = END;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case END:
      exit(1);
      break;
  }
}

Lassen Sie uns zum Schluss die als switchState() bekannte Methode aufrufen und ihr die Ereignisse einzeln in Form von Argumenten bereitstellen.

int main(void) {
  switchState(START_LOOPING);
  switchState(SHOW_MESSAGE);
  switchState(STOP_LOOPING);
  return 0;
}

Es folgt der vollständige Quellcode mit der Anweisung switch.

#include <stdio.h>
#include <stdlib.h>

enum states {
  START,
  ITERATE,
  END,
} state;

enum events {
  START_LOOPING,
  SHOW_MESSAGE,
  STOP_LOOPING,
};

void switchState(enum events event) {
  switch (state) {
    case START:
      switch (event) {
        case START_LOOPING:
          state = ITERATE;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case ITERATE:
      switch (event) {
        case SHOW_MESSAGE:
          printf("State Machine Ready!\n");
          break;
        case STOP_LOOPING:
          state = END;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case END:
      exit(1);
      break;
  }
}

int main(void) {
  switchState(START_LOOPING);
  switchState(SHOW_MESSAGE);
  switchState(STOP_LOOPING);
  return 0;
}

Ausgang:

State Machine Ready!
Waqar Aslam avatar Waqar Aslam avatar

I am Waqar having 5+ years of software engineering experience. I have been in the industry as a javascript web and mobile developer for 3 years working with multiple frameworks such as nodejs, react js, react native, Ionic, and angular js. After which I Switched to flutter mobile development. I have 2 years of experience building android and ios apps with flutter. For the backend, I have experience with rest APIs, Aws, and firebase. I have also written articles related to problem-solving and best practices in C, C++, Javascript, C#, and power shell.

LinkedIn