2011-09-18 41 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是由鏈接器在後臺生成的;它將調用映射到具有該函數的函數,即使這兩個函數存在於不同的源文件中。