gpt4 book ai didi

c - 在 C 中使用 GOTO 进行 FSM

转载 作者:行者123 更新时间:2023-12-02 09:31:54 25 4
gpt4 key购买 nike

我正在用 C 创建一个有限状态机。我从硬件的角度(HDL语言)学习了FSM。所以我使用了一个 switch,每个状态有一个 case

我也喜欢在编程时应用关注点分离概念。我的意思是我想得到这个流程:

  1. 根据当前状态和输入标志计算下一个状态
  2. 验证下一个状态(如果用户请求不允许的转换)
  3. 在允许时处理下一个状态

一开始我实现了 3 个功能: 静态 e_InternalFsmStates fsm_GetNextState(); 静态 bool_t fsm_NextStateIsAllowed(e_InternalFsmStates nextState); 静态无效 fsm_ExecuteNewState(e_InternalFsmStates);

目前它们都包含一个相同的大开关盒:

switch (FSM_currentState) {
case FSM_State1:
[...]
break;
case FSM_State2:
[...]
break;
default:
[...]
break;
}

现在它可以工作了,我想改进代码。

我知道在 3 个函数中我将执行 switch 的相同分支。所以我想以这种方式使用 gotos:

//
// Compute next state
//
switch (FSM_currentState) {
case FSM_State1:
next_state = THE_NEXT_STATE
goto VALIDATE_FSM_State1_NEXT_STATE;
case FSM_State2:
next_state = THE_NEXT_STATE
goto VALIDATE_FSM_State2_NEXT_STATE;
[...]
default:
[...]
goto ERROR;
}

//
// Validate next state
//
VALIDATE_FSM_State1_NEXT_STATE:
// Some code to Set stateIsValid to TRUE/FALSE;
if (stateIsValid == TRUE)
goto EXECUTE_STATE1;
else
goto ERROR;

VALIDATE_FSM_State2_NEXT_STATE:
// Some code to Set stateIsValid to TRUE/FALSE;
if (stateIsValid == TRUE)
goto EXECUTE_STATE2;
else
goto ERROR;

//
// Execute next state
//
EXECUTE_STATE1:
// Do what I need for state1
goto END;

EXECUTE_STATE2:
// Do what I need for state2
goto END;

//
// Error
//
ERROR:
// Error handling
goto END;

END:
return; // End of function

当然,我可以在单个 switch 案例中完成 3 个部分(计算、验证和处理下一个状态)。但是对于代码可读性和代码审查,我觉得将它们分开会更容易。

最后我的问题是,以这种方式使用 GOTO 是否危险?你对这样使用 FSM 有什么建议吗?

感谢您的意见!


阅读下面的答案和评论后,这是我要尝试的:

e_FSM_InternalStates nextState = FSM_currentState;
bool_t isValidNextState;

//
// Compute and validate next state
//
switch (FSM_currentState) {
case FSM_State1:
if (FSM_inputFlags.flag1 == TRUE)
{
nextState = FSM_State2;
}
[...]

isValidNextState = fsm_validateState1Transition(nextState);

case FSM_State2:
if (FSM_inputFlags.flag2 == TRUE)
{
nextState = FSM_State3;
}
[...]
isValidNextState = fsm_validateState2Transition(nextState);
}


//
// If nextState is invalid go to Error
//
if (isValidNextState == FALSE) {
nextState = FSM_StateError;
}


//
// Execute next state
//
switch (nextState) {
case FSM_State1:
// Execute State1
[...]

case FSM_State2:
// Execute State1
[...]

case FSM_StateError:
// Execute Error
[...]
}

FSM_currentState = nextState;

最佳答案

虽然 goto 在 C 语言中有它的优点,但应该谨慎使用它。你想要的不是可推荐的用例。

您的代码将难以维护且更加困惑。 switch/case 实际上是某种“计算”的 goto(这就是为什么会有 case labels)。

你基本上是想错了。对于状态机,您应该首先验证输入,然后计算下一个状态,然后是输出。有多种方法可以做到这一点,但使用两个开关和(可能)一个错误处理标签或一个错误标志通常是个好主意:

bool error_flag = false;

while ( run_fsm ) {
switch ( current_state ) {

case STATE1:
if ( input1 == 1 )
next_state = STATE2;
...
else
goto error_handling; // use goto
error_flag = true; // or the error-flag (often better)
break;

...
}

if ( error_flag )
break;

switch ( next_state ) {

case STATE1:
output3 = 2;
// if outputs depend on inputs, similar to the upper `switch`
break;
...
}

current_state = next_state;
}

error_handling:
...

通过这种方式,您可以同时转换和验证输入。这很有意义,因为无论如何您都必须评估输入以设置下一个状态,因此无效输入自然会落在测试中。

另一种方法是使用 output_statestate 变量代替 next_statecurrent_state。在第一个 switch 中你设置了 output_statestate,第二个是 switch ( output_state ) ...

如果单个 case 变得太长,您应该使用函数来确定 next_state 和/或 output_state/输出。这在很大程度上取决于 FSM(输入、输出、状态、复杂性的数量(例如 one-hot 与“编码” - 如果您是 HDL 的家人,您就会知道)。

如果您需要在循环内进行更复杂的错误处理(例如恢复),请保持循环不变并添加一个外部循环,可能会将错误标志更改为错误代码并在外循环。根据复杂程度,将内循环打包成自己的函数等。

旁注:编译器可能会很好地将结构化方法(没有 goto)优化为与 goto

相同/相似的代码

关于c - 在 C 中使用 GOTO 进行 FSM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32182876/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com