【问题标题】:How to handle error in C?如何处理C中的错误?
【发布时间】:2017-04-22 04:05:31
【问题描述】:

说,我有这样的代码:

int foo() {
    ...
    int buff_size;
    scanf("%d", &buff_size);
    FILE * fp = fopen("./file", "a+");
    char *buff = malloc(buff_size*sizeof(char));
    char *buff2 = malloc(buff_size*sizeof(char));
    char *buff3 = malloc(buff_size*sizeof(char));
    while (!feof(fp)) {
        /*do something, say read, write etc.*/
        if (/*error case 1*/) {
            free(buff);
            free(buff1);
            free(buff3);
            fclose(fp);
            return -1;
        }
        else if (/*error case 2*/) {
            free(buff);
            free(buff1);
            free(buff3);
            fclose(fp);
            return -2;
        }
        ...
        else if (/*error case k*/) {
            free(buff);
            free(buff1);
            free(buff3);
            fclose(fp);
            return -k;
        }
    }
    ...
    free(buff);
    free(buff1);
    free(buff2);
    fclose(fp);
    return 0;
    }

对于 C 不提供 try...throw...finally 语法,我必须关闭文件描述符并释放我在返回错误整数代码之前创建的堆内存指针。它会产生一些重复的代码,使代码变得丑陋。

有人知道我应该如何修改这种代码以使其看起来更简洁吗?

【问题讨论】:

标签: c error-handling


【解决方案1】:

你写的代码相当于

    FILE * fp = fopen("./file", "a+");
    int return_value = 0;                  /*  assume zero means no error */
    char *buff = malloc(1024*sizeof(char));
    char *buff2 = malloc(1024*sizeof(char));
    char *buff3 = malloc(1024*sizeof(char));

    while (feof(fp))
    {
        /*do something, say read, write etc.*/
        if (/*error case 1*/)
        {
            return_value = -1;
        }
        else if (/*error case 2*/)
        {
            return_value = -2;
        }
        // ...
        else if (/*error case k*/)
        {
            return_value = -k;
        }
    }

    if (return_value == 0)   /* if no error has occurred, we can still do stuff  */
    {
        ...
    }

    /*   I have assumed all buffers need to be released 
         and files closed as the function returns
    */

    free(buff);
    free(buff1);     /*  you probably intend buff2 and buff3 here, to match the malloc() calls */
    free(buff2);
    fclose(fp);
    return return_value;
}

但是,我还没有解决您代码中的两个严重错误。你需要。

  • fopen() 可能会失败,并返回 NULL。如果是这样,将其传递给feof()fclose() 会给出未定义的行为。您的代码根本没有检查,在调用 feof()fclose() 之前都需要。
  • while (!feof(fp)) {read_something_from(fp); use_something();} 形式的循环是个坏主意。请查看Why is “while ( !feof (file) )” always wrong? 了解更多信息。

不太重要 - 对于固定大小的数组(大小在编译时固定),您可能不需要使用malloc(),这也意味着您不需要使用free()。但是,您仍然需要处理fopen() 的潜在故障。

【讨论】:

  • 不应该留下while-loop以防出错吗?
  • @alk - 我不建议避免 while 循环。我说while(!feof())(特别是)是个坏主意。
【解决方案2】:

对于这种带有常见清理代码的事情,我会使用一个返回值变量和一个goto

int foo() {
    ...
    // append extended mode ... what are you doing with this?
    FILE * fp = fopen("./file", "a+");
    char buff[1024];
    char buff2[1024];
    char buff3[1024];

    int ret = 0;

    while (/* file I/O is valid on fp */) {
        /*do something, say read, write etc.*/
        if (/*error case 1*/) {
            ret = -1;
            goto cleanup;
        }
        else if (/*error case 2*/) {
            ret = -2;
            goto cleanup;
        }
        ...
        else if (/*error case k*/) {
            ret = -k;
            goto cleanup;
        }
    }
    ...
cleanup:
    free(buff);
    free(buff2);
    free(buff3);
    fclose(fp);
    return ret;
}

这也避免了复制粘贴代码或重新输入错误(就像您当前的代码一样)。

【讨论】:

  • 请阅读上面关于feofwhile 外观中的使用的评论
  • 已编辑。现在 OP 应该选择他们的“有效”表达式。
  • 使用goto() 是一个可怕的想法。结果是“意大利面条”代码。编写一个处理清理并将其所需的任何参数值传递给它的“子”函数要好得多。
猜你喜欢
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多