基于C语言函数指针的有限状态机(FSM)优化实现问询
优化版有限状态机(FSM)实现(基于函数指针)
Hey there! I took a look at your FSM implementation using function pointers, and it's a solid start. Let's walk through some optimizations to clean up redundancy, fix logical gaps, and meet all your requirements (like state entry messages and a proper SetState API). Here's a refined version that's more maintainable and aligns better with embedded system best practices:
Key Optimizations & Improvements
- Encapsulated State Machine Data: Replaced global variables with a struct to avoid polluting the global namespace (critical for embedded systems with multiple modules)
- Eliminated Redundant Code: Moved repetitive input handling and state validation logic into helper functions
- Implemented State Entry Messages: Added required print statements like
Current State is drivingwhen entering a state - Proper
SetStateAPI: Created the requested API to trigger state transitions externally - Clearer State Transition Logic: Each state function only defines valid transitions, making the FSM easier to debug and extend
- Safer Input Handling: Added bounds checking for user input to prevent invalid state values
Complete Compilable Code
#include <stdio.h> #include <stdbool.h> // Define drive states with descriptive names typedef enum { PARK = 0, NEUTRAL = 1, DRIVE = 2, REVERSE = 3, STATE_COUNT } DriveState_t; // Forward declarations for state functions DriveState_t state_park(DriveState_t target); DriveState_t state_neutral(DriveState_t target); DriveState_t state_drive(DriveState_t target); DriveState_t state_reverse(DriveState_t target); // State machine struct to encapsulate all FSM data typedef struct { DriveState_t current_state; // Function pointer array mapping states to their handler functions DriveState_t (*state_handlers[STATE_COUNT])(DriveState_t); } DriveFSM_t; // Global state machine instance (can be static if used in a single module) DriveFSM_t drive_fsm; // Helper function to print state name as string static const char* get_state_name(DriveState_t state) { switch(state) { case PARK: return "parking"; case NEUTRAL: return "neutral"; case DRIVE: return "driving"; case REVERSE: return "reversing"; default: return "unknown"; } } // Helper function to validate if a target state is valid static bool is_valid_state(DriveState_t state) { return (state >= PARK && state < STATE_COUNT); } // State handler: PARK DriveState_t state_park(DriveState_t target) { // Valid transitions from PARK: only to NEUTRAL if (target == NEUTRAL) { printf("\nTransitioning from PARK to NEUTRAL\n"); drive_fsm.current_state = target; printf("Current State is %s\n", get_state_name(target)); } else if (target == PARK) { printf("\nCurrent State remains %s\n", get_state_name(target)); } else { printf("\nInvalid transition from PARK to %d! State remains %s\n", target, get_state_name(drive_fsm.current_state)); } return target; } // State handler: NEUTRAL DriveState_t state_neutral(DriveState_t target) { // Valid transitions from NEUTRAL: PARK, DRIVE, REVERSE if (target == PARK || target == DRIVE || target == REVERSE) { printf("\nTransitioning from NEUTRAL to %s\n", get_state_name(target)); drive_fsm.current_state = target; printf("Current State is %s\n", get_state_name(target)); } else if (target == NEUTRAL) { printf("\nCurrent State remains %s\n", get_state_name(target)); } else { printf("\nInvalid transition from NEUTRAL to %d! State remains %s\n", target, get_state_name(drive_fsm.current_state)); } return target; } // State handler: DRIVE DriveState_t state_drive(DriveState_t target) { // Valid transitions from DRIVE: only to NEUTRAL if (target == NEUTRAL) { printf("\nTransitioning from DRIVE to NEUTRAL\n"); drive_fsm.current_state = target; printf("Current State is %s\n", get_state_name(target)); } else if (target == DRIVE) { printf("\nCurrent State remains %s\n", get_state_name(target)); } else { printf("\nInvalid transition from DRIVE to %d! State remains %s\n", target, get_state_name(drive_fsm.current_state)); } return target; } // State handler: REVERSE DriveState_t state_reverse(DriveState_t target) { // Valid transitions from REVERSE: only to NEUTRAL if (target == NEUTRAL) { printf("\nTransitioning from REVERSE to NEUTRAL\n"); drive_fsm.current_state = target; printf("Current State is %s\n", get_state_name(target)); } else if (target == REVERSE) { printf("\nCurrent State remains %s\n", get_state_name(target)); } else { printf("\nInvalid transition from REVERSE to %d! State remains %s\n", target, get_state_name(drive_fsm.current_state)); } return target; } // SetState API: External interface to request state transition void SetState(DriveState_t target_state) { if (!is_valid_state(target_state)) { printf("\nSetState error: Invalid target state %d\n", target_state); return; } // Trigger the current state's handler with the target state drive_fsm.state_handlers[drive_fsm.current_state](target_state); } // Helper function to get valid user input static DriveState_t get_user_input(void) { int input; printf("\nEnter next state (0=PARK, 1=NEUTRAL, 2=DRIVE, 3=REVERSE, -1=Exit): "); scanf("%d", &input); if (input == -1) { return PARK; // Exit by returning PARK (matches original loop condition) } // Validate input bounds if (is_valid_state((DriveState_t)input)) { return (DriveState_t)input; } else { printf("Invalid input! Please enter a value between 0-3 or -1 to exit.\n"); return get_user_input(); // Recursively get valid input } } int main(void) { // Initialize state machine drive_fsm.current_state = PARK; drive_fsm.state_handlers[PARK] = state_park; drive_fsm.state_handlers[NEUTRAL] = state_neutral; drive_fsm.state_handlers[DRIVE] = state_drive; drive_fsm.state_handlers[REVERSE] = state_reverse; printf("Starting State Machine at currentState: %s\n", get_state_name(drive_fsm.current_state)); DriveState_t target_state; do { target_state = get_user_input(); if (target_state != -1) { SetState(target_state); } } while (target_state != PARK); // Exit when user selects PARK or -1 printf("\nExiting State Machine at Current State: %s\n", get_state_name(drive_fsm.current_state)); return 0; }
What's Improved Compared to Your Original Code?
- Encapsulation: All FSM data (current state, handler functions) lives in a
DriveFSM_tstruct, which is much cleaner than global variables. This makes it easy to have multiple FSM instances if needed. - State Entry Messages: Every valid transition prints the required message like
Current State is drivingwhen entering the DRIVE state. SetStateAPI: The requested API is fully implemented, providing a clean external interface to trigger state changes (perfect for integrating with CAN messages or other input sources in embedded systems).- Reduced Redundancy: Helper functions like
get_state_nameandis_valid_stateeliminate repeated code across state handlers. Input validation is centralized instead of being duplicated in each function. - Clearer Transition Logic: Each state handler explicitly defines valid transitions, making it easy to modify or extend the FSM (e.g., add a new state like LOW_GEAR later).
- Safer Input Handling: The
get_user_inputfunction validates user input and recursively asks for valid input if needed, preventing invalid state values from crashing the FSM. - Readability: Using
typedeffor enums and structs makes the code more readable, and state names are converted to strings for user-friendly output.
You can compile and run this code directly, and it should behave as expected while being much easier to maintain and extend for your embedded system needs.
内容的提问来源于stack exchange,提问作者SAI SRIKAR
相关产品推荐
相关产品推荐

