2

我有以下代码来定义我的 FSM 状态:

enum states
{
    START,              // Send request to remote IP or wait for a request (WAIT_CONN_REQ)
    WAIT_RESP,          // Chat request sent to remote IP. Waiting for a response from the target machine
    SEND_CONN_RESP,     // Chat request received from remote IP. ACCEPT or REJECT
    ACCEPTED            // Both parties agreed to exchange datagrams. Begin application data (MESSAGES) exchange
};
typedef enum states states;
states state;

我的思考过程是这样的:我的聊天程序会有上述四种状态。巧妙地做到这一点的最佳方法是什么?当然,使用 switch 语句。那么我该怎么做呢?像这样:(代码被简化并替换为printf 函数”

int main(int argc, char *argv[])
{
    state = START;
    switch (state)
    {
        case START:
            printf("Simple Chat Client - START state\n");
            if (argv[1] != NULL)
            {
                SEND_CONN_REQ();
                } else {
                WAIT_CONN_REQ();
            }
            break;
        case WAIT_RESP:
            printf("WAIT_RESP STATE!");
            break;
        case SEND_CONN_RESP:
            printf("SEND_CONN_RESP state!");
            break;
        case ACCEPTED:
            printf("ACCEPTED state!");
            break;
    }
}

但这不符合我的要求。我希望它在满足条件时跳转到另一个案例。像这样:

    if (argv[1] != NULL)
                    {
                        SEND_CONN_REQ();
                        goto case WAIT_RESP;          
                        } else {
                        WAIT_CONN_REQ();
                    }
                    break;
                case WAIT_RESP:
                    printf("WAIT_RESP STATE!");
                    break;

我的逻辑告诉我,这样做的方法是更改state​​变量,假设整体switch将使用新变量再次执行。但发生的情况是,我必须要么使用break并退出switch,要么不使用它并让程序执行下一个case.

So I looked at other options, like do statements and continue. But everywhere I look, using case seems to be the way to go with an FSM.

I would appreciate any help on how to do this properly. Is a switch statement even the best way to go?

4

2 回答 2

2

The normal way to code a state machine like that is using a loop and a switch:

state = START;
while (state != STOP)
{
    switch (state)
    {
        case START:
            printf("Simple Chat Client - START state\n");
            if (argv[1] != NULL)
            {
                SEND_CONN_REQ();
            } else {
                WAIT_CONN_REQ();
            }
            break;
        case WAIT_RESP:
            printf("WAIT_RESP STATE!");
            break;
        case SEND_CONN_RESP:
            printf("SEND_CONN_RESP state!");
            break;
        case ACCEPTED:
            printf("ACCEPTED state!");
            break;
    }
}

Each action can optionally set the new state so that the next iteration will do the appropriate actions. Don't forget to output newlines at the ends of printf() statements if you want to see the output in a timely manner. It may not matter on Windows; it does on other platforms.

于 2013-10-20T03:48:41.510 回答
1

If you will always just want to execute the state right below where you are, you could remove the break statement. I would put a comment in it's place like /* fall through */ so that it is clear that it is intentionally missing for people who follow, as well as your future-forgetting self. I personally don't like this method.

Why not change the state variable, and then just execute a goto that is right above the switch statement? Like this maybe:

switchStart:
    switch (state)
    {
        case START:
            printf("Simple Chat Client - START state\n");
            if (argv[1] != NULL)
            {
                SEND_CONN_REQ();
                state = STATE_HERE; // change your state
                goto switchStart; // jump to the top of the switch
                } else {
                WAIT_CONN_REQ();
            }
            break;
        case WAIT_RESP:
            printf("WAIT_RESP STATE!");
            break;
        case SEND_CONN_RESP:
            printf("SEND_CONN_RESP state!");
            break;
        case ACCEPTED:
            printf("ACCEPTED state!");
            break;
    }
于 2013-10-20T03:44:35.917 回答