C中的错误处理策略?

时间:2010-05-03 01:11:53

标签: c

鉴于以下代码:

typedef struct {int a;} test_t;

arbitrary_t test_dosomething(test_t* test) {
    if (test == NULL) {
        //options:
        //1. print an error and let it crash
          //e.g. fprintf(stderr, "null ref at %s:%u", __FILE__, __LINE__);
        //2. stop the world
          //e.g. exit(1);
        //3. return (i.e. function does nothing)
        //4. attempt to re-init test
    }
    printf("%d", test->a); //do something w/ test
}

如果test永远是NULL,我想得到一个编译器错误,但我想这在C中是不可能的。因为我需要在运行时进行空检查,哪种选项是最合适的方式处理它?<​​/ p>

8 个答案:

答案 0 :(得分:7)

如果您不希望使用空指针调用该函数(即,指针不为null是调用函数的前提条件),则可以在函数顶部使用断言:

assert(test != NULL);

这可以帮助您在调试时查找代码中使用空指针调用函数的位置。

答案 1 :(得分:4)

我们真的不能断然回答这个问题。它在很大程度上取决于软件将用于什么。如果它提供辐射,您会希望它打印错误exit(1);。如果您正在编写业务应用程序,则可能需要记录错误并返回。 这完全取决于上下文。

答案 2 :(得分:1)

我会在函数的开头使用一个断言:

arbitrary_t test_dosomething(test_t* test) {
    assert(test != NULL);
    printf("%d", test->a); //do something w/ test
}

您不会收到编译器错误。但是在开发(调试)时,程序将停止并指向代码中的特定assert

答案 3 :(得分:1)

使用setjmp

http://en.wikipedia.org/wiki/Setjmp.h

http://aszt.inf.elte.hu/~gsd/halado_cpp/ch02s03.html

#include <setjmp.h>
#include <stdio.h>

jmp_buf x;

void f()
{
    longjmp(x,5); // throw 5;
}

int main()
{
    // output of this program is 5.

    int i = 0;

    if ( (i = setjmp(x)) == 0 )// try{
    {
        f();
    } // } --> end of try{
    else // catch(i){
    {
        switch( i )
        {
        case  1:
        case  2:
        default: fprintf( stdout, "error code = %d\n", i); break;
        }
    } // } --> end of catch(i){
    return 0;
}

答案 4 :(得分:0)

这实际上取决于您的用例。如果您有交互式应用程序,请提示并让用户更正输入。如果是服务器进程,则可能需要进行日志记录。如果错误将使您的程序向南移动,则执行断言。

答案 5 :(得分:0)

如果test为NULL,它是一个运行时值,并且它甚至可能依赖于用户输入,编译器也无法知道它的值。

要避免使用NULL值调用函数,请使用assert:

assert(test != NULL);

这意味着:我的代码无法将NULL作为输入处理。它会在运行时中止。

你的函数应该返回arbitrary_t并且它没有返回任何东西。

你也可以在你现在没有使用的返回值中将错误发送回调用者,例如返回一个arbitrary_t *,如果无法分配则为NULL(这将是这种情况)如果test_t是NUL)。调用者需要测试它。

答案 6 :(得分:0)

显然(我最近在网上搜索了“C静态断言”),C ++ 0x有一个static_assert,而C人正在谈论类似的东西以及下一个C标准。当然,这意味着C中目前没有标准的“静态断言”。

有人建议使用布尔表达式定义枚举或结构的C预处理器宏,如果条件表达式失败,则使用?:运算符生成非法的枚举/结构定义。 (上面的网络搜索列出了许多这样的宏定义。)

就个人而言,无论如何我总是使用gcc,我只是声明了

这样的功能
foo_t function(moo_t *moo) __attribute__(( nonnull(1) ));

并且因此如果我不小心调用参数设置为-Wnonnull的函数,编译器会给我一个警告(-Wall,包含在NULL中)。

答案 7 :(得分:0)

我只能回应上述内容 - 这取决于你的申请。

一个好的经验法则是尽早发现错误。这通常使得查找和纠正问题变得更容易,更快速和更便宜。理想情况下,你会在设计时抓住这个。正如您所指出的那样,您无法在编译时捕获它(除非切换到像Eiffel这样的“按合同设计”语言),因此您可以在运行时捕获它。

然后......这取决于......

如果它是一个桌面应用程序,那么可能是一个巨大的对话框和退出是修复它的最快方法,如果它导致某人报告错误。如果可以,也可以向开发人员发送电子邮件(例如,如果它是内部应用程序)。

如果它是任务关键型或生命关键型,您可能只需重新启动应用程序(这是嵌入式系统中的一般方法)。

无论您做出什么决定,都要尽可能多地收集有关问题的信息。例如,您可以滚动您的赢取的宏来包装ASSERT,其中添加文件 LINE )。

我使用以下内容:

#ifdef TESTING
#define ASSERT_MSG(subsystem, message, condition) if (!(condition)) {printf("Assert failed: \"%s\" at line %d in file \"%s\"\n", message, __LINE__, __FILE__); fflush(stdout); abort();}

/* we can also use this, which prints of the failed condition as its message */
#define ASSERT_CONDITION(subsystem, condition) if (!(condition)) {printf("Assert failed: \%s\" at line %d in file \%s\"\n", #condition, __LINE__, __FILE__); fflush(stdout); abort();}
#else
#define ASSERT_MSG(subsystem, message, condition)  if (!condition) DebugTrace(FATAL, subsystem, __FILE__, __LINE__, "%s", message);
#define ASSERT_CONDITION(subsystem, condition)     if (!(condition)) DebugTrace(FATAL, subsystem, __FILE__, __LINE__, "%s", #condition);
#endif