To use goto or not?

后端 未结 9 1269
Happy的楠姐
Happy的楠姐 2020-12-14 17:34

This question may sound cliched, but I am in a situation here.

I am trying to implement a finite state automaton to parse a certain string in C. As I started writin

9条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-14 18:31

    I don't know your specific code, but is there a reason something like this:

    typedef enum {
        STATE1, STATE2, STATE3
    } myState_e;
    
    void myFsm(void)
    {
        myState_e State = STATE1;
    
        while(1)
        {
            switch(State)
            {
                case STATE1:
                    State = STATE2;
                    break;
                case STATE2:
                    State = STATE3;
                    break;
                case STATE3:
                    State = STATE1;
                    break;
            }
        }
    }
    

    wouldn't work for you? It doesn't use goto, and is relatively easy to follow.

    Edit: All those State = fragments violate DRY, so I might instead do something like:

    typedef int (*myStateFn_t)(int OldState);
    
    int myStateFn_Reset(int OldState, void *ObjP);
    int myStateFn_Start(int OldState, void *ObjP);
    int myStateFn_Process(int OldState, void *ObjP);
    
    myStateFn_t myStateFns[] = {
    #define MY_STATE_RESET 0
       myStateFn_Reset,
    #define MY_STATE_START 1
       myStateFn_Start,
    #define MY_STATE_PROCESS 2
       myStateFn_Process
    }
    
    int myStateFn_Reset(int OldState, void *ObjP)
    {
        return shouldStart(ObjP) ? MY_STATE_START : MY_STATE_RESET;
    }
    
    int myStateFn_Start(int OldState, void *ObjP)
    {
        resetState(ObjP);
        return MY_STATE_PROCESS;
    }
    
    int myStateFn_Process(int OldState, void *ObjP)
    {
        return (process(ObjP) == DONE) ? MY_STATE_RESET : MY_STATE_PROCESS;
    }
    
    int stateValid(int StateFnSize, int State)
    {
        return (State >= 0 && State < StateFnSize);
    }
    
    int stateFnRunOne(myStateFn_t StateFns, int StateFnSize, int State, void *ObjP)
    {
        return StateFns[OldState])(State, ObjP);
    }
    
    void stateFnRun(myStateFn_t StateFns, int StateFnSize, int CurState, void *ObjP)
    {
        int NextState;
    
        while(stateValid(CurState))
        {
            NextState = stateFnRunOne(StateFns, StateFnSize, CurState, ObjP);
            if(! stateValid(NextState))
                LOG_THIS(CurState, NextState);
            CurState = NextState;
        }
    }
    

    which is, of course, much longer than the first attempt (funny thing about DRY). But it's also more robust - failure to return the state from one of the state functions will result in a compiler warning, rather than silently ignore a missing State = in the earlier code.

提交回复
热议问题