Отличный способ обработки ошибки malloc без проверки, был ли возвращен NULL после каждого вызова malloc? - PullRequest
7 голосов
/ 18 сентября 2011

В моем коде почти каждая функция имеет один или несколько вызовов malloc, и каждый раз мне приходится делать что-то вроде:

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

это четыре дополнительные строки кода, и если я добавлю их каждый раз после того, как использую malloc, длина моего кода сильно увеличится ... так есть ли элегантный способ справиться с этим?

Спасибо большое !!

Ответы [ 8 ]

6 голосов
/ 18 сентября 2011

Обычно нет смысла пытаться запнуться, когда вся память занята.Можете также назвать это броском:

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;
}
3 голосов
/ 18 сентября 2011

Вы можете использовать макросы. Это дешевле, чем группировать этот код в функцию, потому что у макросов нет накладных расходов, которые вызывает вызов функции. Макросы расширяются на этапе препроцессора компиляции и могут быть проверены с помощью опции '-E' в gcc. Теперь скажите, что у нас есть 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
3 голосов
/ 18 сентября 2011

Извините, но вы ничего не можете с этим поделать в C. За исключением ... вздох ... оберните все это в макрос , который автоматизирует проверку if и позволит вам писать пользовательские код обработки ошибок каждый раз. Там я это сказал.

Серьезно, C не предназначен для обеспечения таких удобств. Если вы не возражаете выйти из программы на месте, вы можете обернуть ее в функцию, которая, конечно, выполняет exit при неудачном распределении - но это не общее решение.

1 голос
/ 18 сентября 2011

Когда у вас нет реальной обработки ошибок (кроме печати чего-либо и выхода), простое и устоявшееся решение - определить функцию safe_malloc, которая включает проверку. (Правка: или, конечно же, макрос. Что бы ни качало твою лодку.)

0 голосов
/ 17 января 2017

Или вы можете использовать экстерьер.

Определить функцию в 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);    
}

Любой файл, который выделяет память, добавляется так же, как и в случае предварительного объявления:

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 memory, и main.c, который обрабатывает исключение, генерируется компоновщиком за кулисами; он сопоставляет вызовы функции с функцией, даже если они существуют в разных исходных файлах.

0 голосов
/ 29 июля 2016
#define my_malloc_macro(size, ptr) do { \
    ptr = malloc(size); \
    if(!ptr) { \
        printf("malloc failed\n"); \
        return -1; \
    } \
} while(0)
0 голосов
/ 21 декабря 2015

Среда выполнения 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 голосов
/ 18 сентября 2011

Если условие ошибки всегда так просто (распечатать сообщение об ошибке и вернуться), вы можете переписать, чтобы сохранить строки.

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...