C言語の関数ポインタで実装する状態遷移
2026-02-06
設計
状態遷移
はじめに
今までC言語で状態遷移を実装するときに、switch文を使った実装をしていました。 しかし、switch文が点在して、追加実装漏れが発生する可能性があります。 そこで今回は、関数ポインタを使った状態遷移を作成したので、共有します。
今回実装する状態遷移
今回は、以下のような状態遷移を実装します。
- 状態は以下の2つ
- 状態A
- 状態B
- 各状態に始めて遷移したときに、変数を初期化する
- 各状態でカウンターをインクリメントする
switch文による状態遷移の実装
switch文での実装は次のようになります。
#include <stdbool.h>#include <stdio.h>
// 状態を定義typedef enum { STATE_A, STATE_B, STATE_NUM,} EState;
// 状態Aで使用する構造体typedef struct { int count;} StateAContext;
// 状態Bで使用する構造体typedef struct { int count;} StateBContext;
void state_a_on_enter(StateAContext* ctx) { printf("enter to stateA\n"); ctx->count = 0;}
EState state_a_do(StateAContext* ctx) { printf("stateA\n"); ctx->count++;
if (ctx->count >= 3) { return STATE_B; }
return STATE_A;}
void state_b_on_enter(StateBContext* ctx) { printf("enter to stateB\n"); ctx->count = 0;}
EState state_b_do(StateBContext* ctx) { printf("stateB\n"); ctx->count++;
if (ctx->count >= 2) { return STATE_A; }
return STATE_B;}
int main(void) { StateAContext ctx_a = {0}; StateBContext ctx_b = {0};
EState now = STATE_A; EState prev = STATE_NUM; const int count = 10; for (int i = 0; i < count; i++) { if (prev != now) { switch (now) { case STATE_A: state_a_on_enter(&ctx_a); break; case STATE_B: state_b_on_enter(&ctx_b); break; default: break; } }
prev = now; switch (now) { case STATE_A: now = state_a_do(&ctx_a); break; case STATE_B: now = state_b_do(&ctx_b); break; default: break; } }}関数ポインタによる状態遷移の実装
#include <stdbool.h>#include <stdio.h>
typedef enum { STATE_A, STATE_B, STATE_NUM,} EState;
typedef struct { int count;} StateAContext;
typedef struct { int count;} StateBContext;
typedef union { StateAContext a; StateBContext b;} Context;
void state_a_on_enter(Context* ctx) { printf("enter to stateA\n"); ctx->a.count = 0;}
EState state_a_do(Context* ctx) { printf("stateA\n"); ctx->a.count++;
if (ctx->a.count >= 3) { return STATE_B; } else { return STATE_A; }}
void state_b_on_enter(Context* ctx) { printf("enter to stateB\n"); ctx->b.count = 0;}
EState state_b_do(Context* ctx) { printf("stateB\n"); ctx->b.count++;
if (ctx->b.count >= 2) { return STATE_A; } else { return STATE_B; }}
typedef void (*on_enter_fn)(Context* ctx);typedef EState (*do_fn)(Context* ctx);
typedef struct State { on_enter_fn on_enter; do_fn on_do;} State;
int main(void) { const State states[STATE_NUM] = { [STATE_A] = { .on_enter = state_a_on_enter, .on_do = state_a_do, }, [STATE_B] = { .on_enter = state_b_on_enter, .on_do = state_b_do, }, };
Context ctx = {0};
EState now = STATE_A; EState prev = STATE_NUM; const int N = 10; for (int i = 0; i < N; i++) { if (prev != now) { states[now].on_enter(&ctx); }
prev = now; now = states[now].on_do(&ctx); }}まとめ
C言語での状態遷移の実装パターン(switch文を使用した場合、関数ポインタを使用した場合)の紹介をしました。
同じカテゴリの記事
2026-02-06
C言語の関数ポインタで実装する状態遷移