是否使用goto?

Abh*_*yay 20 c parsing goto finite-automata

这个问题可能听起来有些陈词滥调,但我处于这种情况.

我正在尝试实现一个有限状态自动机来解析C中的某个字符串.当我开始编写代码时,我意识到如果我使用标签来标记不同的状态并使用goto从一个状态跳转到另一个案件来了.

在这种情况下使用标准的break和flag变量非常麻烦,很难跟踪状态.

什么方法更好?最重要的是,我担心这会给我的老板留下不好的印象,因为我正在实习.

bta*_*bta 36

没有什么本质上的错误goto.它们通常被认为是"禁忌"的原因是因为一些程序员(通常来自汇编世界)使用它们来创建几乎无法理解的"意大利面条"代码.如果您可以goto在保持代码清洁,可读和无错误的同时使用语句,那么您将获得更多权力.

goto为每个状态使用语句和一段代码绝对是编写状态机的一种方法.另一种方法是创建一个变量,该变量将保持当前状态并使用switch语句(或类似)来根据状态变量的值选择要执行的代码块.请参阅Aidan Cully使用第二种方法获得良好模板的答案.

实际上,这两种方法非常相似.如果使用状态变量方法编写状态机并对其进行编译,则生成的程序集可能非常类似于使用该goto方法编写的代码(取决于编译器的优化级别).该goto方法可以看作是从状态变量方法优化额外变量和循环.你使用哪种方法是个人选择的问题,只要你正在编写工作的,可读的代码,我希望你的老板不会认为你使用一种方法而不是另一种方法.

如果要将此代码添加到已包含状态机的现有代码库中,我建议您遵循已使用的任何约定.

  • 在遵循已经使用的任何惯例方面都有智慧 (3认同)

Jer*_*fin 19

使用a goto来实现状态机通常很有意义.如果您真的担心使用goto,合理的替代方法通常state是使用您修改的变量,以及switch基于此的声明:

typedef enum {s0,s1,s2,s3,s4,...,sn,sexit} state;

state nextstate;
int done = 0;

nextstate = s0;  /* set up to start with the first state */
while(!done)
   switch(nextstate)
      {
         case s0:
            nextstate = do_state_0();
            break;
         case s1:
            nextstate = do_state_1();
            break;
         case s2:
            nextstate = do_state_2();
            break;
         case s3:
             .
             .
             .
             .
         case sn:
            nextstate = do_state_n();
            break;
         case sexit:
            done = TRUE;
            break;
         default:
            /*  some sort of unknown state */
            break;
      }
Run Code Online (Sandbox Code Playgroud)


Vin*_*vic 15

如果我想给老板留下好印象,我会像Ragel一样使用FSM发生器.

这种方法的主要好处是,您可以在更高的抽象级别描述您的状态机,而不需要关心是否使用goto或switch.更不用说在Ragel的特定情况下,您可以自动获得FSM的漂亮图表,在任何点插入操作,自动最小化状态量和各种其他好处.我是否提到生成的FSM也非常快?

缺点是它们更难调试(自动可视化在这里有很多帮助)并且你需要学习一个新工具(如果你有一台简单的机器并且你不太可能经常编写机器,这可能是不值得的. )

  • 我在使用非平凡代码生成器时遇到的问题是:1)调试,以及2)学习新工具的需要......如果该工具给了我一些有用的东西,没有它就很难实现,或者如果我将使用该工具足以弥补学习它的时间投入(注意可调试性是一个重要的因素),太棒了,我会做的.我不会为一个微不足道的FSM而烦恼,但可能是一个更复杂的FSM. (3认同)
  • 我不会提倡GOTO,因为FSM生成器会这样做.创建GOTO的代码生成器(可能已经过测试)和执行它的程序员之间存在差异.我不知道要走哪条路.但我不会让发电机使用GOTO这一事实影响决策(当然,如果我正在编写一台发电机来做这件事......). (3认同)

R S*_*hko 10

我会使用一个跟踪你所处状态的变量和一个处理它们的开关:

fsm_ctx_t ctx = ...;
state_t state = INITIAL_STATE;

while (state != DONE)
{
    switch (state)
    {
    case INITIAL_STATE:
    case SOME_STATE:
        state = handle_some_state(ctx)
        break;

    case OTHER_STATE:
        state = handle_other_state(ctx);
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)


Fem*_*ref 8

Goto不是必要的邪恶,我不得不强烈反对Denis,是的,在大多数情况下goto可能是一个坏主意,但有一些用途.goto最大的恐惧是所谓的"spagetti-code",无法追踪的代码路径.如果你可以避免这种情况,如果它总是很清楚代码的行为方式,并且你没有用goto跳出函数,那就没有什么可以反对goto了.请谨慎使用它,如果您想要使用它,请真正评估情况并找到更好的解决方案.如果您不能这样做,可以使用goto.


wal*_*lyk 8

避免goto,除非增加的复杂性(避免)较为混乱.

在实际的工程问题中,可以非常谨慎地使用goto.学者和非工程师不必要地用手指敲打他们goto.也就是说,如果你把自己描绘成一个实现角落,其中很多goto是唯一的出路,重新考虑解决方案.

正确工作的解决方案通常是主要目标.使其正确和可维护(通过最小化复杂性)具有许多生命周期益处.首先使其工作,然后逐渐清理,最好通过简化和去除丑陋.