当前位置:  开发笔记 > 编程语言 > 正文

当我已经返回一个值时,从函数返回错误的最佳方法是什么?

如何解决《当我已经返回一个值时,从函数返回错误的最佳方法是什么?》经验,为你挑选了4个好方法。

我在C中编写了一个函数,它将字符串转换为整数并返回整数.当我调用该函数时,我也希望它告诉我字符串是不是有效数字.在过去,当发生此错误时,我返回-1,因为我不需要将字符串转换为负数.但现在我希望它将字符串转换为负数,那么报告错误的最佳方法是什么?

如果我不清楚这一点:我不希望此函数向用户报告错误,我希望它将错误报告给调用该函数的代码.("报告"可能是错误的用词...)

这是代码:

s32 intval(const char *string) {
    bool negative = false;
    u32 current_char = 0;

    if (string[0] == '-') {
        negative = true;
        current_char = 1;
    }

    s32 num = 0;
    while (string[current_char]) {
        if (string[current_char] < '0' || string[current_char] > '9') {
            // Return an error here.. but how?
        }

        num *= 10;
        num += string[current_char] - '0';
        current_char++;
    }

    if (negative) {
        num = -num;
    }

    return num;
}

Michael Burr.. 35

有几种方法.所有人都有他们的优点和缺点.

让函数返回错误代码并传入指向某个位置的指针以返回结果.关于这一点的好处是没有结果的重载.不好的是你不能直接在表达式中使用函数的实际结果.

Evan Teran提出了一个变体,它使调用者传递一个指向成功变量的指针(如果调用者不关心,可以选择为NULL)并返回函数的实际值.这样做的好处是,当调用者在错误结果中使用默认值或者知道函数不能失败时,允许函数直接在表达式中使用.

使用特殊的"sentinel"返回值来指示错误,例如负数(如果正常返回值不能为负数),INT_MAX或者INT_MIN如果良好值不能达到极值.有时为了获得更详细的错误信息,需要查询另一个函数(例如GetLastError())或全局变量(例如errno).如果您的返回值没有无效值,并且一般被许多人视为不良格式,则此方法无效.

使用此技术的示例函数是getc(),如果到达文件末尾或遇到错误,则返回EOF.

让函数永远不会直接返回错误指示,但要求调用者查询另一个函数或全局函数.这类似于VB的" On Error Goto Next"模式的工作原理 - 它几乎被普遍认为是一种糟糕的方式.

另一种方法是拥有"默认"值.例如,atoi()函数与函数intval()几乎完全相同,当它无法转换任何字符时将返回0(它与函数的不同之处在于它消耗字符进行转换,直到它到达字符串的末尾或者不是数字的字符).

这里明显的缺点是,判断实际值是否已转换或是否已传递垃圾可能很棘手atoi().

我不是这种处理错误的忠实粉丝.

我会更新,因为其他选项在我脑海中浮现......



1> Michael Burr..:

有几种方法.所有人都有他们的优点和缺点.

让函数返回错误代码并传入指向某个位置的指针以返回结果.关于这一点的好处是没有结果的重载.不好的是你不能直接在表达式中使用函数的实际结果.

Evan Teran提出了一个变体,它使调用者传递一个指向成功变量的指针(如果调用者不关心,可以选择为NULL)并返回函数的实际值.这样做的好处是,当调用者在错误结果中使用默认值或者知道函数不能失败时,允许函数直接在表达式中使用.

使用特殊的"sentinel"返回值来指示错误,例如负数(如果正常返回值不能为负数),INT_MAX或者INT_MIN如果良好值不能达到极值.有时为了获得更详细的错误信息,需要查询另一个函数(例如GetLastError())或全局变量(例如errno).如果您的返回值没有无效值,并且一般被许多人视为不良格式,则此方法无效.

使用此技术的示例函数是getc(),如果到达文件末尾或遇到错误,则返回EOF.

让函数永远不会直接返回错误指示,但要求调用者查询另一个函数或全局函数.这类似于VB的" On Error Goto Next"模式的工作原理 - 它几乎被普遍认为是一种糟糕的方式.

另一种方法是拥有"默认"值.例如,atoi()函数与函数intval()几乎完全相同,当它无法转换任何字符时将返回0(它与函数的不同之处在于它消耗字符进行转换,直到它到达字符串的末尾或者不是数字的字符).

这里明显的缺点是,判断实际值是否已转换或是否已传递垃圾可能很棘手atoi().

我不是这种处理错误的忠实粉丝.

我会更新,因为其他选项在我脑海中浮现......


我上面的建议是返回结果并让param成为指向成功变量的指针.如果您不关心它允许传递NULL,但也允许您直接在表达式中使用返回值.
另一种选择是返回包含成功/错误状态的复杂对象(例如,数组或散列映射),然后返回实际结果(如果成功)或错误标识符(如果失败).许多非RESTful JSON API执行此操作,忽略HTTP状态代码.

2> Jon Skeet..:

那么,.NET在Int32.TryParse中处理它的方式是返回成功/失败,并使用pass-by-reference参数传回解析后的值.同样可以在C中应用:

int intval(const char *string, s32 *parsed)
{
    *parsed = 0; // So that if we return an error, the value is well-defined

    // Normal code, returning error codes if necessary
    // ...

    *parsed = num;
    return SUCCESS; // Or whatever
}


说实话,这两种方式都很奇怪 - 但这种方式意味着你可以编写if(intval(text,&result)){...}
@Korchkidu:无论如何我更愿意检查 - 否则就像是在驾驶停车场时系上安全带,但是当你在开阔的道路上时将它取下来.

3> Evan Teran..:

一种常见的方法是将指针传递给成功标志,如下所示:

int my_function(int *ok) {
    /* whatever */
    if(ok) {
        *ok = success;
    }
    return ret_val;
}

这样叫:

int ok;
int ret = my_function(&ok);
if(ok) {
    /* use ret safely here */
}

编辑:这里的示例实现:

s32 intval(const char *string, int *ok) {
    bool negative = false;
    u32 current_char = 0;

    if (string[0] == '-') {
        negative = true;
        current_char = 1;
    }

    s32 num = 0;
    while (string[current_char]) {
        if (string[current_char] < '0' || string[current_char] > '9') {
                // Return an error here.. but how?
                if(ok) { *ok = 0; }
        }

        num *= 10;
        num += string[current_char] - '0';
        current_char++;
    }

    if (negative) {
        num = -num;
    }
    if(ok) { *ok = 1; }
    return num;
}

int ok;
s32 val = intval("123a", &ok);
if(ok) {
    printf("conversion successful\n");
}



4> S.Lott..:

os风格的全局errno变量也很受欢迎.使用errno.h.

如果errno不为零,则出现问题.

这是errno的手册页参考.


我不认为很多人都喜欢errno,尽管当C标准化时,它已经存在先例.例如,参见PJ Plauger的"标准C库".
@Jonathan Leffler:同意,不喜欢errno.但问题集中在C上,这个问题是C语言标准的,众所周知的问题之一.使用errno是该问题的标准着名解决方案.
推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有