如何处理C语言中的错误?

如何处理C语言中的错误?,c,error-handling,C,Error Handling,比如,我有这样的代码: 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(buf

比如,我有这样的代码:

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语法,所以在返回错误整数代码之前,我必须关闭我创建的文件描述符和释放堆内存指针。它会产生一些重复的代码,使代码变得丑陋


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

对于这类常见的清理代码,我会使用一个返回值变量和一个
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;
}

这还可以防止复制粘贴代码,或重新键入有错误的代码(正如您当前的代码一样)。

对于常见的清理代码,我将使用一个返回值变量和一个
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;
}

这还可以防止复制粘贴代码或重新键入有错误的代码(正如您当前的代码一样)。

您编写的代码相当于

    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()
    之前检查这两个属性
  • 当(!feof(fp)){read_something_from(fp);use_something();}时,使用
    形式的循环是个坏主意。查看以获取更多信息

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

的潜在故障,因为编写的代码相当于

    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()
    之前检查这两个属性
  • 当(!feof(fp)){read_something_from(fp);use_something();}时,使用
    形式的循环是个坏主意。查看以获取更多信息

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

的潜在故障。如果您总是分配相同的固定大小,为什么不使用数组?也请阅读为什么你把这个标记为C++?<代码> siZoof(char)< /C>总是1。<代码> C++ +<代码>标签应该从这个问题中删除。因为,在
c++
中的答案将不同于
c
中的答案。关于c中“try-catch”的讨论很好:如果总是分配相同的固定大小,为什么不使用数组呢?也请阅读为什么你把这个标记为C++?<代码> siZoof(char)< /C>总是1。<代码> C++ +<代码>标签应该从这个问题中删除。因为,在
c++
中的答案将不同于
c
中的答案。关于c中“try catch”的良好讨论:请阅读上面关于
feof
中使用的注释,而
looksEdited。现在OP应该选择他们的“is valid”表达式。使用
goto()
是一个可怕的想法。结果是“意大利面条”代码。最好编写一个“sub”函数来处理清理,并将所需的任何参数值传递给它。请阅读上面关于
while
looksEdited中使用
feof
的注释。现在OP应该选择他们的“is valid”表达式。使用
goto()
是一个可怕的想法。结果是“意大利面条”代码。最好编写一个“sub”函数来处理清理并向其传递所需的任何参数值。如果出现任何错误,是否应该保留
while
-循环?@alk-我不建议避免
while
循环。我说
while(!feof())
(特别是)是个坏主意。如果出现任何错误,不应该保留
while
-循环吗?@alk-我不建议避免
while
循环。我说,
,而(!feof())
(具体地说)是个坏主意。