我如何正确处理C中的malloc失败,尤其是当有多个malloc时? [英] How can I correctly handle malloc failure in C, especially when there is more than one malloc?

查看:767
本文介绍了我如何正确处理C中的malloc失败,尤其是当有多个malloc时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设这是我的代码的一部分:

 int foo()
 {  
    char *p, *q ;
    if((p = malloc(BUFSIZ)) == NULL) {
        return ERROR_CODE;
    }
    if((q = malloc(BUFSIZ)) == NULL) {
        free(p)
        return ERROR_CODE;
    }
    /* Do some other work... */

    free(p);
    free(q);  
 }

由于第一个malloc可能成功但第二个malloc失败,所以我在第二个错误处理程序"中使用free(p).但是,如果还有更多malloc,又想修改代码(调整其顺序,添加或删除一些malloc)怎么办?

我知道在C ++中有诸如RAII和异常安全之类的东西.但是,总的来说,处理C中malloc失败的正确方法是什么? (也许使用某些goto?)

解决方案

您的代码很好,但是对于很多变量,我希望:

int
foo()
{
    char *p = NULL;
    char *q = NULL;
    int ret = 0;

    if (NULL == (p = malloc(BUFSIZ)))
    {
        ret = ERROR_CODE;
        goto error;
    }

    // possibly do something here

    if (NULL == (q = malloc(BUFSIZ)))
    {
        ret = ERROR_CODE;
        goto error;
    }

    // insert similar repetitions

    // hopefully do something here

  error:
    free (p);
    free (q);
    return ret;
}

请注意,释放NULL被定义为无操作.

这避免了n变量的n缩进级别.您可以类似地清理文件句柄等(尽管您必须在close()周围加上条件).

现在,如果您知道可以一次分配它们,那么 dasblinkenlight 有一个很好的答案,但这是另一种方法:

int
foo()
{
    int ret = 0;
    char *p = malloc(BUFSIZ);
    char *q = malloc(BUFSIZ);
    char *r = malloc(BUFSIZ);
    if (!p || !q || !r)
    {
        ret = ERROR_CODE;
        goto exit;
    }

    // do something

  exit:
    free(p);
    free(q);
    free(r);
    return ret;
}

最后的可能性:如果您实际上想在malloc失败时退出程序,请考虑使用malloptM_CHECK_ACTION选项.这样可以检查malloc()故障,并调用abort(),可能会显示一条有用的消息.

在手册页中:

NAME

mallopt-设置内存分配参数

简介

  #include <malloc.h>

  int mallopt(int param, int value);

说明

mallopt()函数可调整控制内存分配功能行为的参数(请参见malloc(3)). param参数指定要修改的参数,而value指定该参数的新值.

可以为param指定以下值:

M_CHECK_ACTION

设置此参数可控制在检测到各种编程错误(例如,释放同一指针两次)时glibc的响应方式.分配给该参数的值的3个最低有效位(2、1,和0)确定glibc行为,如下所示:

位0 :如果设置了此位,则在stderr上打印一条单行消息,其中提供有关错误的详细信息.消息以字符串"*** glibc detected ***"开头,后跟程序名称,检测到错误的内存分配函数的名称,错误的简要说明以及检测到错误的内存地址.

位1 :如果设置了此位,则在打印由位0指定的任何错误消息后,将通过调用abort(3)终止程序.在从2.4开始的glibc版本中,如果还设置了位0,则在打印错误消息和中止之间,程序还将以backtrace(3)的方式打印堆栈跟踪,并以(请参见proc(5)).

位2 :(自glibc 2.4起)仅当还设置了位0时,此位才有效.如果设置了此位,则描述错误的单行消息将简化为仅包含检测到错误的函数的名称以及错误的简要说明.

Suppose this is a part of my code:

 int foo()
 {  
    char *p, *q ;
    if((p = malloc(BUFSIZ)) == NULL) {
        return ERROR_CODE;
    }
    if((q = malloc(BUFSIZ)) == NULL) {
        free(p)
        return ERROR_CODE;
    }
    /* Do some other work... */

    free(p);
    free(q);  
 }

Since it's possible that the first malloc is successful but the second one fails, I use free(p) in the second "error handler". But what if there are more malloc's and what if I want to modify the code (adjusting their orders, adding or deleting some malloc)?

I know in C++ there are things like RAII and exception safe, etc. But in general, what is the correct way to handle malloc failure in C? (maybe using some goto?)

解决方案

Your code is fine, but for lots of variables, I'd prefer:

int
foo()
{
    char *p = NULL;
    char *q = NULL;
    int ret = 0;

    if (NULL == (p = malloc(BUFSIZ)))
    {
        ret = ERROR_CODE;
        goto error;
    }

    // possibly do something here

    if (NULL == (q = malloc(BUFSIZ)))
    {
        ret = ERROR_CODE;
        goto error;
    }

    // insert similar repetitions

    // hopefully do something here

  error:
    free (p);
    free (q);
    return ret;
}

Note that freeing NULL is defined as a no-op.

This avoids n levels of indent for n variables. You can clean up filehandles etc. similarly (though you'll have to put a condition around the close()).

Now, if you know you can allocate them all at once, then dasblinkenlight has a good answer, but here's another way:

int
foo()
{
    int ret = 0;
    char *p = malloc(BUFSIZ);
    char *q = malloc(BUFSIZ);
    char *r = malloc(BUFSIZ);
    if (!p || !q || !r)
    {
        ret = ERROR_CODE;
        goto exit;
    }

    // do something

  exit:
    free(p);
    free(q);
    free(r);
    return ret;
}

Final possibility: if you actually want to exit the program on malloc fail, consider using mallopt's M_CHECK_ACTION option. This makes malloc() faults get checked, and calls abort(), possibly printing a helpful message.

From the man page:

NAME

mallopt - set memory allocation parameters

SYNOPSIS

  #include <malloc.h>

  int mallopt(int param, int value);

DESCRIPTION

The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that parameter.

The following values can be specified for param:

M_CHECK_ACTION

Setting this parameter controls how glibc responds when various kinds of programming errors are detected (e.g., freeing the same pointer twice). The 3 least significant bits (2, 1, and 0) of the value assigned to this parameter determine the glibc behavior, as follows:

Bit 0: If this bit is set, then print a one-line message on stderr that provides details about the error. The message starts with the string "*** glibc detected ***", followed by the program name, the name of the memory-allocation function in which the error was detected, a brief description of the error, and the memory address where the error was detected.

Bit 1: If this bit is set, then, after printing any error message specified by bit 0, the program is terminated by calling abort(3). In glibc versions since 2.4, if bit 0 is also set, then, between printing the error message and aborting, the program also prints a stack trace in the manner of backtrace(3), and prints the process's memory mapping in the style of /proc/[pid]/maps (see proc(5)).

Bit 2: (since glibc 2.4) This bit has an effect only if bit 0 is also set. If this bit is set, then the one-line message describing the error is simplified to contain just the name of the function where the error was detected and the brief description of the error.

这篇关于我如何正确处理C中的malloc失败,尤其是当有多个malloc时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆