1. 枚举 + 函数指针法
    这种方法通过 enum 来定义所有可能的状态,每个状态对应一个处理函数。状态切换是通过函数指针数组来完成的。这种方法适合较为复杂的状态机,状态间的行为是相互独立的,可以灵活扩展。

优点:

代码清晰,容易扩展。
独立的状态函数使得每个状态的行为和处理逻辑都很直观。
实现示例:

#include <stdio.h>

typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_STOPPED,
    STATE_MAX
} State;

// 状态处理函数
void state_idle(void) {
    printf("Device is in Idle state.\n");
}

void state_running(void) {
    printf("Device is in Running state.\n");
}

void state_stopped(void) {
    printf("Device is in Stopped state.\n");
}

// 函数指针数组,用来映射状态到对应的处理函数
void (*state_func[STATE_MAX])(void) = {state_idle, state_running, state_stopped};

int main() {
    State current_state = STATE_IDLE;

    // 模拟状态机运行
    while (1) {
        state_func[current_state]();  // 调用当前状态的函数
        current_state = (current_state + 1) % STATE_MAX; // 循环状态
    }

    return 0;
}

  1. 状态转换表
    状态转换表方法使用一个二维数组,其中行表示当前状态,列表示触发事件。表中的值表示状态转移后的状态。通过查找表来决定下一个状态。这种方式适合事件驱动的状态机,通常用于状态和事件之间有明确映射的场景。

优点:

适用于状态和事件之间的规则简单且固定的场景。
代码结构紧凑,状态和事件的映射清晰。
实现示例:

#include <stdio.h>

typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_STOPPED,
    STATE_MAX
} State;

typedef enum {
    EVENT_START,
    EVENT_STOP,
    EVENT_PAUSE,
    EVENT_MAX
} Event;

// 状态转换表:行是当前状态,列是事件
State state_transition[STATE_MAX][EVENT_MAX] = {
    {STATE_RUNNING, STATE_IDLE, STATE_IDLE},  // STATE_IDLE
    {STATE_RUNNING, STATE_STOPPED, STATE_IDLE},  // STATE_RUNNING
    {STATE_IDLE, STATE_IDLE, STATE_IDLE}  // STATE_STOPPED
};

void handle_event(State *current_state, Event event) {
    *current_state = state_transition[*current_state][event];
    switch (*current_state) {
        case STATE_IDLE: printf("Idle State\n"); break;
        case STATE_RUNNING: printf("Running State\n"); break;
        case STATE_STOPPED: printf("Stopped State\n"); break;
    }
}

int main() {
    State current_state = STATE_IDLE;
    handle_event(&current_state, EVENT_START);  // 触发开始事件
    handle_event(&current_state, EVENT_STOP);   // 触发停止事件
    handle_event(&current_state, EVENT_PAUSE);  // 触发暂停事件
    return 0;
}

  1. 状态机结构体法
    这种方法通过定义一个结构体来封装每个状态的信息,每个状态包含进入、退出和运行时的操作。适合更复杂的状态机,每个状态有自己独立的行为和生命周期管理。

优点:

每个状态的行为是封装的,代码更加模块化。
可以独立管理每个状态的操作,如进入、退出等。
实现示例:

#include <stdio.h>

typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_STOPPED,
    STATE_MAX
} State;

typedef struct {
    State state;
    void (*enter)(void);  // 进入状态时的操作
    void (*exit)(void);   // 离开状态时的操作
    void (*run)(void);    // 当前状态的执行操作
} StateMachine;

// 状态操作函数
void enter_idle(void) { printf("Entering Idle State\n"); }
void exit_idle(void) { printf("Exiting Idle State\n"); }
void run_idle(void) { printf("Running Idle State\n"); }

void enter_running(void) { printf("Entering Running State\n"); }
void exit_running(void) { printf("Exiting Running State\n"); }
void run_running(void) { printf("Running Running State\n"); }

StateMachine fsm[STATE_MAX] = {
    {STATE_IDLE, enter_idle, exit_idle, run_idle},  // STATE_IDLE
    {STATE_RUNNING, enter_running, exit_running, run_running},  // STATE_RUNNING
    {STATE_STOPPED, NULL, NULL, NULL}  // STATE_STOPPED
};

int main() {
    fsm[STATE_IDLE].enter();  // 进入空闲状态
    fsm[STATE_IDLE].run();    // 执行空闲状态操作
    fsm[STATE_IDLE].exit();   // 离开空闲状态

    fsm[STATE_RUNNING].enter();  // 进入运行状态
    fsm[STATE_RUNNING].run();    // 执行运行状态操作
    fsm[STATE_RUNNING].exit();   // 离开运行状态

    return 0;
}

  1. 基于 switch 的状态机
    这种方法直接使用 switch 语句来实现状态转移。适用于状态和事件较少且逻辑简单的场景。它实现起来简单直接,但对于复杂的状态机,代码可能变得冗长且难以扩展。

优点:

实现简单,适合状态较少的场景。
代码直接,容易理解。
实现示例:

#include <stdio.h>

typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_STOPPED
} State;

int main() {
    State current_state = STATE_IDLE;
    while (1) {
        switch (current_state) {
            case STATE_IDLE:
                printf("Idle State\n");
                current_state = STATE_RUNNING;  // 状态转换
                break;
            case STATE_RUNNING:
                printf("Running State\n");
                current_state = STATE_STOPPED;  // 状态转换
                break;
            case STATE_STOPPED:
                printf("Stopped State\n");
                current_state = STATE_IDLE;  // 状态转换
                break;
        }
    }
    return 0;
}

总结:
枚举 + 函数指针法:适合复杂的状态机,每个状态有独立的处理函数,扩展性好。
状态转换表:适用于状态和事件之间的转换规则简单且明确的场景,代码简洁。
状态机结构体法:适合需要封装更多信息的状态机,每个状态可以有独立的进入、退出、执行操作。
switch 语句法:适合状态较少且逻辑简单的场景,快速实现。
选择哪种方式取决于你的需求。如果需要更复杂的行为或状态间的转换逻辑,可以考虑使用枚举 + 函数指针法或状态机结构体法;如果状态和事件比较简单,可以使用状态转换表或 switch 语句法。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐