处理malloc错误的巧妙方法,而不检查每次malloc调用后是否返回NULL?
在我的代码中,几乎每个函数都有一个或多个malloc调用,每次我必须执行以下操作:
char *ptr = (char *)malloc(sizeof(char) * some_int); if (ptr == NULL) { fprintf(stderr, "failed to allocate memory.\n"); return -1; }
这是额外的四行代码,如果我在使用malloc后每次都添加它们,我的代码长度会增加很多..所以有一种优雅的方法来处理这个问题吗?
非常感谢!!
对不起,但在C中没有什么可以做的。除了…… 喘息…将它全部包装在宏中 ,这将自动执行if
检查并允许您每次编写自定义error handling代码。 在那里,我说了。
说真的,C并不意味着提供这样的便利。 如果您不介意当场退出该程序,您可以将其包装在当然在分配失败时exit
的function中 – 但这不是一般解决方案。
在消耗所有内存时,尝试偶然发现并不是很重要。 不妨称之为退出:
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; }
你可以使用宏。 这比将此代码分组到函数中要便宜,因为宏没有函数调用所产生的开销。 宏通过编译的预处理器阶段进行扩展,可以通过gcc中的“-E”选项进行validation。 现在说我们有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
当你没有真正的error handling(除了打印和退出)之外,简单而成熟的解决方案是定义一个包含检查的函数safe_malloc。 (编辑:或者,当然,还有一个宏。无论你的船是什么岩石。)
如果错误条件始终如此简单(打印错误消息并返回),则可以重写以保存行。
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);
C运行时应该清理所有资源,包括打开文件,缓冲区和分配的数据。 即便如此,我喜欢使用int atexit( void(*)(void))
,它会在正常退出时调用注册函数。 如果atexit
返回非零值,也会立即退出,这意味着您的函数未注册。
#include 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 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 ; }
#define my_malloc_macro(size, ptr) do { \ ptr = malloc(size); \ if(!ptr) { \ printf("malloc failed\n"); \ return -1; \ } \ } while(0)
或者你可以使用extern。
在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内存的代码中的位置与处理exception的main.c之间的链接是由链接器在后台生成的; 即使两个源文件存在于不同的源文件中,它也会将调用映射到函数。