使用用户定义的函数检查malloc是否成功是不是一个坏主意?

时间:2016-09-10 16:03:48

标签: c malloc

在C中使用malloc时,我总是被告知通过检查是否返回NULL值来检查是否发生了任何错误。虽然我完全理解为什么这很重要,但是在我们内部输入'if'语句以及我想要的任何内容来检查内存是否已成功分配给我使用malloc的每个单独实例时,有点麻烦。为了使事情更快,我做了如下功能来检查它是否成功。

#define MAX 25
char MallocCheck(char* Check);
char *Option1, *Option2;
int main(){
    Option1 = (char *)malloc(sizeof(char) * MAX);
    MallocCheck(Option1);
    Option2 = (char *)malloc(sizeof(char) * MAX);
    MallocCheck(Option2);
    return 0;
}

char MallocCheck(char* Check){
    if(Check == NULL){
        puts("Memory Allocation Error");
        exit(1);
    }
}

但是,无论我搜索多少,我都没有见过别人做过这样的事情,所以我认为这是错误的,或者其他不应该做的事情。

为此目的使用用户定义的函数是错误的,如果是这样,为什么会这样呢?

2 个答案:

答案 0 :(得分:0)

错误检查是一个好的事物。

使帮助函数更快地编码,更好的是良好的事物。

细节取决于编码目标和您小组的编码标准。

OP的方法也不错。我更喜欢用分配来处理错误。 stderr @EOF上的以下输出,并且在分配0个字节时不会抱怨NULL返回(这不是内存不足)。

void *malloc_no_return_on_OOM(size_t size) {
  void *p = mallc(size);
  if (p == NULL && size > 0) {
    // Make messages informative
    fprintf(stderr, "malloc(%zu) failure\n", size);
    // or 
    perror("malloc() failure");
    exit(1);
  }
  return p;
}

高级:可以使用宏来编码包含调用者函数和行的DEBUG版本。

答案 1 :(得分:0)

这是@ chux的回答和评论的附录。

如上所述,DRY代码通常是一件好事,malloc错误通常在特定实现中以相同的方式处理。

确实有些系统(特别是Linux)提供了乐观的malloc实现,这意味着malloc总是返回一个有效的指针(从不NULL)并且使用信号报告错误第一次将数据写入返回的指针...这使得错误处理比问题中的代码稍微复杂一些。

但是,将错误检查移到另一个函数可能会导致性能下降,除非编译器/链接器发现问题并优化函数调用。

这是内联函数(在较新的编译器上)或宏的经典用例。

#include <signal.h>

void handle_no_memory(int sig) {
  if (sig == SIGSEGV) {
    perror("Couldn't allocate or access memory");
    /* maybe use longjmp to stay in the game...? Or not... */
    exit(SIGSEGV);
  }
}

/* Using a macro: */
#define IS_MEM_VALID(ptr)                                                      \
  if ((ptr) == NULL) {                                                         \
    handle_no_memory(SIGSEGV);                                                 \
  }
/* OR an inline function: */
static inline void *is_mem_valid(void *ptr) {
  if (ptr == NULL)
    handle_no_memory(SIGSEGV);
  return ptr;
}

int main(int argc, char const *argv[]) {
  /* consider setting a signal handler - `sigaction` is better, but I'm lazy. */
  signal(SIGSEGV, handle_no_memory);
  /* using the macro */
  void *data_macro = malloc(1024);
  IS_MEM_VALID(data_macro);
  /* using the inline function */
  void *data_inline = is_mem_valid(malloc(1024));
}

宏和内联函数都会阻止代码跳转和函数调用,因为if语句现在是函数的一部分而不是外部函数。

使用inline时,编译器将获取汇编代码并将其放在函数内(而不是执行函数调用)。为此,我们必须信任编译器,以便它正常工作(它通常比我们更好)。

使用宏时,预处理器会处理事情,我们不需要信任编译器。

在这两种情况下,函数/宏都是文件的本地(注意static关键字),允许编译器(而不是链接器)执行任何优化。

祝你好运。