C のステート マシン
この記事では、C プログラミング言語でのステート マシンの実装について説明します。
ステート マシンの概要
ステート マシンを使用してコードを実装することは、複雑なエンジニアリングの問題を解決するための貴重な設計戦略です。 ステート マシンは、全体的な設計を受け取り、ステート マシンの専門用語で状態と呼ばれる段階に分割します。
すべての州は、特定の機能を実行する責任があります。 一方、イベントは、ステート マシンを状態間で変化させる刺激です。 トランジション
とも呼ばれます。
最初に作成されたとき、ほとんどのシステムは簡単でよく整理されていますが、新しい機能が追加されると、イベントの履歴を追跡するために追加のフラグと変数が作成されます。
次に、if
ステートメントと else
ステートメントを追加して、多くの変数とフラグから作成されたますます複雑な論理式をテストします。
この点で、ステート マシンが役に立ちます。 ステート マシンを適切に使用すると、各分岐点でテストされる条件が簡素化され、プログラム実行のさまざまなモード間の切り替え
が容易になります。
ほとんどのリアルタイム システムの動作は、比較的少数の重複しないチャンク (状態) に分割できることがわかります。
各チャンク内のイベント応答は、現在のイベントのみに依存し、過去に発生した一連のイベントには依存しなくなりました。
Function Pointers
を使用してステート マシンを作成する
以下は、C でステート マシンを構築するコードの例です。この特定の例では、2つの 状態 スイッチを 10 回前後に生成します。
次に、インデックス番号とそのインデックスに対応する状態を表示します。
#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);
}
出力:
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
Switch
ステートメントを使用してステート マシンを作成する
確実なスタートを切るには、プログラムが存在する可能性のある一連の 状態
と、プログラムが処理できる一連の イベント
をリストする必要があります。
このプログラムは、START,
、ITERATE,
、または END
の 3つの状態のいずれかになります。
enum states {
START,
ITERATE,
END,
} state;
イベント START LOOPING
、SHOW_MESSAGE
、および STOP LOOPING
を処理できます。 START
状態で START LOOPING
イベントを受け取った後、プログラムは ITERATE
状態に遷移します。
ITERATE
状態にある間、SHOW_MESSAGE
イベントを受信するとメッセージが表示されます。 最後に、STOP LOOPING
イベントを受信した後、END
状態に遷移します。
enum events {
START_LOOPING,
SHOW_MESSAGE,
STOP_LOOPING,
};
現在の状態を見て適切なケースを実行する switch
ステートメントを使用してみましょう。 START
、ITERATE
および END
と呼ばれる 3つの主な状況があります。
START
ケース内で、受信したイベントが START LOOPING
の場合、状態が ITERATE
に変更されます。 イベントが START LOOPING
でない場合、ケースは壊れます。
同様に、ITERATE
の場合、受信したイベントが SHOW MESSAGE
の場合、メッセージが表示されます。 それ以外の場合は、STOP LOOPING
ケースをチェックし、状態を END
に変更します。
これらのイベントのいずれも受信されない場合、中断して次のケースに進みます。 最後に、END
ケースにより switch
ステートメントが終了し、プログラムが終了します。
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;
}
}
最後に、switchState()
として知られるメソッドを呼び出して、一度に 1つずつ引数の形式でイベントを提供します。
int main(void) {
switchState(START_LOOPING);
switchState(SHOW_MESSAGE);
switchState(STOP_LOOPING);
return 0;
}
以下は、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;
}
出力:
State Machine Ready!
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