在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);
}
}
但是,无论我搜索多少,我都没有见过别人做过这样的事情,所以我认为这是错误的,或者其他不应该做的事情。
为此目的使用用户定义的函数是错误的,如果是这样,为什么会这样呢?
答案 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
关键字),允许编译器(而不是链接器)执行任何优化。