Neat way to handle malloc error without checking i

2020-07-10 05:25发布

In my code almost every function has one or more malloc calls, and each time I have to do something like:

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

that's four extra lines of code and if I add them everytime after I use a malloc, the length of my code will increase a lot.. so is there an elegant way to deal with this?

Thank you so much!!

标签: c
8条回答
▲ chillily
2楼-- · 2020-07-10 05:38

Sorry, but there's nothing you can do about that in C. Except... gasp... wrap it all in a macro which will automate the if check and allow you to write custom error-handling code each time. There, I said it.

Seriously, C isn't meant to provide conveniences like this. If you don't mind exiting the program on the spot, you can wrap it in a function of course that does exit when the allocation fails -- but that's no general solution.

查看更多
我想做一个坏孩纸
3楼-- · 2020-07-10 05:39

When you have no real error handling (except printing something and exiting), the simple and established solution is to define a function safe_malloc which incorporates the check. (Edit: Or, of course, a macro. Whatever rocks your boat.)

查看更多
相关推荐>>
4楼-- · 2020-07-10 05:41

There isn't usually much point in trying to stumble on when all memory is consumed. Might as well call it quits:

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;
}
查看更多
做自己的国王
5楼-- · 2020-07-10 05:42

You could use macros. This is cheaper than grouping this code into a function because Macros don't have the overhead a function call incurs. Macros are expanded by the preprocessor stage of compilation and can be verified by the '-E' option in gcc. Now say we have 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
查看更多
干净又极端
6楼-- · 2020-07-10 05:47

Or you could use an extern.

Define a function in 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);    
}

Any file that mallocs memory add as you would a forward declaration:

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

Now write malloc as:

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

The linkage between the place in your code where you malloc'd memory and main.c that handles the exception is generated behind the scenes by the linker; it maps calls to the function with the function even though the two exist in different source files.

查看更多
等我变得足够好
7楼-- · 2020-07-10 05:50

C runtime should clean up any resources, including open files, buffers, and allocated data. Even so, I like to use int atexit( void(*)(void)) which will call registered functions upon a normal exit. Also exit immediately if atexit returns a non-zero value, meaning your function was not registered.

#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 ) ;
    }
}

Then exit on malloc failure.

#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 ;
}
查看更多
登录 后发表回答