2011-09-18 90 views
6

在我的代码几乎每一个功能都有一个或多个malloc的电话,每一次我必须做一些事情,如:整洁的方式来处理malloc错误,而不检查每次malloc调用后是否返回NULL?

char *ptr = (char *)malloc(sizeof(char) * some_int); 
if (ptr == NULL) { 
    fprintf(stderr, "failed to allocate memory.\n"); 
    return -1; 
} 

这是代码四个额外的行,如果我加入他们,我用一个malloc后每次,我的代码长度会增加很多..那么有没有一种优雅的方式来处理这个问题?

非常感谢你!

+0

如果你的代码长度会增加很多,你应该考虑一下你为什么要调用'malloc'这么多。这可能表明你正在尝试将不同语言的成语翻译为C,而不是正确使用C ... –

+3

请注意,不需要在C中投射'malloc'的返回值,并且可能会隐藏编译器在没有演员。 – pmg

+0

@pmg你说的是'(char *)'吧?这掩盖了什么样的错误? – cokedude

回答

3

对不起,但没有什么可以做,在C.除... 喘气......包裹这一切在宏将自动化if检查,并允许您编写自定义错误处理每个码时间。在那里,我说了。

严重的是,C并不意味着提供这样的便利。如果您不介意现场退出该程序,您可以将其包装在分配失败时的exit的功能当中 - 但这不是一般的解决方案。

+4

或者用函数而不是宏包装它。 – 2011-09-18 15:29:30

+2

@WTP:这个函数的问题是它可以检测到这个条件,但是并没有真正处理它。至少不是没有你的努力,你会在每个呼叫站点使用4行代码更好。至少据我所知。 – Jon

1

如果你没有真正的错误处理(除了打印和退出),简单的和已建立的解决方案是定义一个函数safe_malloc,它包含了检查。 (编辑:或者,当然,还有一个宏,不管你的船是什么样的。)

5

当所有的内存耗尽时,通常都没有多少意思。不妨叫它退出:

char* allocCharBuffer(size_t numberOfChars) 
{ 
    char *ptr = (char *)malloc(sizeof(char) * numberOfChars); 
    if (ptr == NULL) { 
     fprintf(stderr, "failed to allocate memory.\n"); 
     exit(-1); 
    } 
    return ptr; 
} 
+0

有些清理程序呢?删除临时文件等 – CMCDragonkai

+0

您可以使用'atexit()' – Alexander

0

如果你的错误条件总是那么简单(打印错误信息和返回),你可以重写保存行。

int errmsg(const char *msg, int retval) { 
    fprintf(stderr, "%s\n", msg); 
    return retval; 
} 

if ((ptr = malloc(size)) == NULL) return errmsg("failed to allocate memory.", -1); 
/* ... */ 
free(ptr); 
3

你可以使用宏。这比将此代码分组到一个函数中要便宜,因为宏没有函数调用发生的开销。宏由编译的预处理器阶段扩展,可以通过gcc中的'-E'选项验证。 现在说我们有FUNC1(),FUNC2(),FUNC3()

#define MY_MALLOC(_ptr,_count, _lbl) \ 
do { \ 
if (NULL == (ptr = malloc(sizeof(char) * _count))) { \ 
    fprintf(stderr, "Failed to allocate memory.\n"); \ 
    goto _lbl; \ 
} \ 
} while(0) 

func1() { 
char *ptr; 
MY_MALLOC(ptr,10,Error); 
.... 
... 
return (0); 
Error: 
return (1); 
} 


func2() { 
char *ptr; 
MY_MALLOC(ptr,10,Error); 
.... 
... 
return (0); 
Error: 
return (1); 
} 


func3() { 
char *ptr; 
MY_MALLOC(ptr,10,Error); 
.... 
... 
return (0); 
Error: 
return (1); 
} 

#undef MY_MALLOC 
0

C运行时应该清理的任何资源,包括打开文件,缓冲区和分配数据。即使如此,我也喜欢使用int atexit(void(*)(void)),它将在正常退出时调用已注册的函数。如果atexit返回非零值,也表示立即退出,这意味着您的功能未被注册。

#include <stdlib.h> 
void register_cleanup (void (*cleaner)(void)) 
{ 
    if (atexit (cleaner)) 
    { 
     fprintf (stderr, "Error, unable to register cleanup: %s\n", 
       strerror (errno)) ; 
     exit (EXIT_FAILURE) ; 
    } 
} 

然后退出malloc失败。

#include <stdlib.h> 
void *malloc_or_die (size_t size) 
{ 
    void *dataOut = malloc (size) ; 
    if (!dataOut) 
    { 
     fprintf (stderr, "Error, malloc: %s\n", strerror (errno)) ; 
     exit (EXIT_FAILURE) ; 
    } 
    return dataOut ; 
} 
void main() 
{ 
    register_cleanup (cleaner_fnc) ; 
    ... 
    void *data = malloc_or_die (42) ; 
    do_stuff (data) ; 
    return 0 ; 
} 
+0

这并没有考虑其他数据在同一功能内被释放,或者没有在'atexit'函数中处理。 Anoop Menon的宏将允许这样做。 如果每个函数的错误处理是不同的,那么不使用宏抽象就会更清楚。 – Funmungus

0
#define my_malloc_macro(size, ptr) do { \ 
    ptr = malloc(size); \ 
    if(!ptr) { \ 
     printf("malloc failed\n"); \ 
     return -1; \ 
    } \ 
} while(0) 
0

或者你可以使用一个外部。

在main中定义一个函数。C:

void sj_handleException(bool fatal, const char* msg, const char* libMsg){ 
    fprintf(stderr, msg); 
    if(libMsg != NULL) fprintf(stderr, libMsg); 

    if(fatal) exit(EXIT_FAILURE);  
} 

是mallocs内存加为你的任何文件将预先声明:

extern void sj_handleException(bool fatal, const char* msg, const char* libMsg) 

现在写的malloc为:

char *ptr = (char *)malloc(sizeof(char) * some_int); 
if (ptr == NULL) sj_handleException(true, "failed to allocate memory.\n", NULL); 

在你的代码中的地方之间的联系你的malloc'd内存和处理异常的main.c是由链接器在后台生成的;它将调用映射到具有该函数的函数,即使这两个函数存在于不同的源文件中。