goto的C用法

问题描述

我有一个带有某种回调机制的状态机,这些函数是由任务运行程序调用的。所有这些的背后是一个状态机,它具有4种状态,有些状态彼此排斥,其他状态可以组合在一起,从而形成了相当复杂的规则集。如果试图进行任何非法操作,其中一个功能显示用户错误消息(为简便起见,printf在这里):

static int state1 = 0;
static bool switch2 = 1;

void do_stuff(int value){
    int errorCode = 0;
    if(state1 == 1){ 
        errorCode = -1;
        goto ERROR;
    }
    if(state1 == 2 && switch2)
    {
        errorCode = 2;
        goto ERROR;
    }


    printf("No error!");
    return;
ERROR:
    printf("%d",errorCode);
}

这是我能想到的最短,最简洁的方法,但是它总是让人们意识到使用goto是一件坏事。有没有更好的方法解决此问题,或者就稳定性和维护而言,这是最好的方法吗?

解决方法

goto是控制流的正确解决方案。尽管goto有有效的用例,但在此特定功能中,您可以像下面这样简单地将控制流重构为if-else分支:

void do_stuff(int value)
{
    int errorCode = 0;

    if (state1 == 1)
    { 
        errorCode = -1;
    }
    else if (state1 == 2 && switch2)
    {
        errorCode = 2;
    }
    else // unconditional case for no errors
    {
        printf("No error!");
        return;
    }
    printf("%s",errorCode);  // if control reaches here,print the error
}
,

据我所知,您使用goto进行错误处理,而不是用于状态机。

使用goto进行错误处理实际上是那些情况非常有用且相对于复杂的条件链而言更受欢迎的情况之一。它使您无需重复代码即可执行手动RAII:

int do_stuff(...)
{
    ... = f1(...);
    if (...)
        goto ERROR_f1;

    ... = f2(...);
    if (...)
        goto ERROR_f2;

    ... = f3(...);
    if (...)
        goto ERROR_f3;

    // Success
    return ...;

ERROR_f3:
    undo_f2(...);

ERROR_f2:
    undo_f1(...);

ERROR_f1:
    return ...;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...