模式,以防止不断检查错误?

时间:2014-07-09 15:49:35

标签: c error-handling embedded

在C中,是否有一种模式可以不再检查调用其他函数的函数中的错误?

e.g。如果函数foo()依次调用a(),b()和c(),则必须在继续之前检查每个函数的返回值。如果a(),b()或c()也调用其他函数,这些函数也可能调用其他函数,这会留下一长串错误检查,可能会出现同样的错误......

int16_t a(x_t x) {return DO_SOME_WORK(x);}

int16_t b(y_t y) {return DO_OTHER_WORK(y);}

int16_t c(z_t z) {return DO_MORE_WORk(z);}

foo (x_t x, y_t y, z_t z) {
    int16_t err = 0;
    // I can handle errors returned by either:
    err = a(x));
    if (err) return err;
    err = b(y);
    if (err) return err;
    err = c(z); 
    return err;

    // Or
    err = a(x);
    if (!err) err = b(y);
    if (!err) err = c(z);
    return err;
}

我更喜欢第二种方法,因为有一个明确的单一退出点,但是另一种方法对处理进行了本地化,并且任何一种方法都引入了很多ifs,并且使用大型程序,这是很多额外的代码,特别是在无效的函数中但是,例如,调用其他函数并传递它们之间的输出。 感谢

3 个答案:

答案 0 :(得分:4)

在这种情况下,您可以利用&&的短路评估,当左侧操作数为false时,不评估右侧操作数。

如果您可能希望在对a()b()c()的调用之间执行其他处理,则以下内容允许:

bool foo (x_t x, y_t y, z_t z) 
{
    bool err = a( x );
    err = err && b( y ) ;
    err = err && c( z ) ; 

    return err;
}

如果该函数仅由调用a()b()c()组成,那么您可以使用更简洁:

bool foo (x_t x, y_t y, z_t z) 
{
    return a( x ) && 
           b( y ) && 
           c( z ) ; 
}

[添加以回应评论]

解决@kkrambo关于函数返回的任何数值没有传播给调用者的观点可以解决,但作为解决方案的吸引力越来越小:

int16_t foo (x_t x, y_t y, z_t z) 
{
    int16_t ret ;

    bool err = (ret = a( x ));
    err = err && (ret = b( y )) ;
    err = err && (ret = c( z )) ; 

    return ret ;
}

int16_t foo (x_t x, y_t y, z_t z) 
{
    uint16_t ret ;

    (ret = a( x )) && 
    (ret = b( y )) && 
    (ret = c( z )) ;

    return ret ; 
}

你甚至可以做得越来越恐怖:

int16_t foo (x_t x, y_t y, z_t z) 
{
    int16_t err ;

    if( (err = a(x)) ) {}
    else if( (err = b(y)) ) {} 
    else if( (err = c(z)) ) {}

    return err ; 
}

简化以下err布尔值:

bool foo (x_t x, y_t y, z_t z) 
{
    bool err = true ;

    if( a(x) ) {}
    else if( b(y) ) {} 
    else if( c(z) ) {}
    else { err = false }

    return err ; 
}

答案 1 :(得分:3)

如果函数的每个函数调用都需要错误检查,那么每次调用该函数时都应检查错误。原因是即使它是相同的函数,输入也是不同的,并且全局(和静态局部)变量是不同的,从而改变结果。这意味着如果你想检查错误,你实际上并没有浪费计算工作。

编辑:我不知道这是否明智但你可以使用宏来清理

的语法
err = a(x);
if(err) return err;

看起来像

#define error_check(f, e) \
e = f; \
if(e) return e;

所以在你的代码中你可以写

error_check(a(x),err)

我没有使用宏来实现,但这应该可行。

答案 2 :(得分:1)

由于目标是返回错误代码而不是简单的布尔值,因此OP提供的两种方法至少是合理的,如果不是更可取的话。像if (a(x) || b(x)) return true这样的短路代码无法维持erra()派生的b()值。

归结为风格。

如果代码简单由几行组成,任何方法都足够了。但鉴于可能存在a(x)b(x)c(x)之间交织的重要代码,建议不要使用样式2,因为它会在多行代码中分隔流。我喜欢风格3超过1,因为它更简洁,但1和1之间的差异。 3很小。

为了应对样式#2在一个位置收集错误返回的能力,考虑一个更高级别的函数包装器,它可以明确地确保所有序言和结尾活动的发生。

最佳选择:遵循团队风格指南,否则最适合您维护,而不是写作。

int16_t foo (x_t x, y_t y, z_t z) {  // added matching return type
    int16_t err = 0;

    // OP style 1
    err = a(x));
    if (err) return err;
    err = b(y);
    if (err) return err;
    err = c(z); 
    return err;

    // OP style 2
    err = a(x);
    if (!err) err = b(y);
    if (!err) err = c(z);
    return err;

    // style 3
    // via enum or define, create an OK symbol
    if ((err = a(x)) != OK) return err;
    if ((err = b(x)) != OK) return err;
    if ((err = c(x)) != OK) return err;
    // 
}