假设我的代码中有以下行:
struct info *pinfo = malloc(sizeof(struct info));
Run Code Online (Sandbox Code Playgroud)
通常还有另一行代码,如下所示:
if (!pinfo)
<handle this error>
Run Code Online (Sandbox Code Playgroud)
但这真的值得吗?特别是如果对象太小以至于生成的检查它的代码可能需要比对象本身更多的内存。
确实,内存不足的情况很少见,特别是对于仅分配数十字节内存的小型测试程序,尤其是在拥有许多千兆字节可用内存的现代系统上。
\n然而malloc失败是很常见的,尤其是对于小型测试程序。
malloc可能会因两个原因而失败:
malloc检测到内存分配堆混乱,可能是因为您之前的内存分配之一出现问题。现在,事实证明#2一直在发生。
\n而且,事实证明 #1 也很常见,虽然不是因为没有足够的内存来满足程序员想要执行的分配,而是因为程序员不小心向 传递了一个巨大的数字,意外地要求了比malloc那里更多的内存是在已知的宇宙中。
所以,是的,事实证明检查malloc失败确实是一个好主意,尽管它看起来malloc“不会失败”。
另一件需要考虑的事情是,如果你走捷径而不检查malloc失败怎么办?如果你继续前进并使用给你的空指针malloc,这将导致你的程序立即崩溃,并且这会提醒你注意你的问题,就像“内存不足”消息一样,而你没有把你的手指磨到骨打字if(!pinfo)上fprintf(stderr, "out of memory\\n"),对吗?
嗯,不。
\n根据您的程序意外地使用空指针执行的操作,它可能不会立即崩溃。不管怎样,你得到的崩溃,以及诸如“分段冲突 - 核心转储”之类的消息并不能告诉你太多,也不能告诉你问题出在哪里。您可能会因为各种原因而遇到分段违规(尤其是在小型测试程序中,尤其是如果您是初学者,不太确定自己在做什么)。您可能会花费数小时徒劳地找出程序崩溃的原因,却没有意识到这是因为malloc返回空指针。因此,当然,您应该始终检查 malloc 失败,即使是在最小的测试程序中。
一般来说,决定测试哪些错误,以及测试哪些“不可能发生”或由于任何原因不值得捕获的错误。可能需要相当多的经验才能知道什么值得检查,什么不值得检查。但是,确实,任何长期使用 C 语言编程的人都可以强调地告诉您:malloc失败绝对值得检查。
如果您的程序到处调用malloc,那么检查每个调用可能会很麻烦。所以一个流行的策略是使用malloc包装器:
void *my_malloc(size_t n)\n{\n void *ret = malloc(n);\n if(ret == NULL) {\n fprintf(stderr, "malloc failed (%s)\\n", strerror(errno));\n exit(1);\n }\n return ret;\n}\nRun Code Online (Sandbox Code Playgroud)\n可以通过三种方式来思考这个函数:
\nmalloc失败)时,看看是否可以将其移至(集中)单个函数,如下所示。malloc,my_malloc不能失败。它永远不会返回空指针。这几乎是魔法。你可以随时随地调用它,而且永远不必检查它的返回值。它让你假装你永远不必担心内存不足(这一直是我们的目标)。my_malloc的好处 \xe2\x80\x94 似乎永远不会失败 \xe2\x80\x94 是有代价的。如果底层malloc失败,my_malloc则立即退出(因为在这种情况下它无法返回),这意味着程序的其余部分没有机会清理. 例如,如果该程序是一个文本编辑器,每当出现一点错误时,它就会打印“内存不足”,然后基本上丢弃用户过去一小时编辑的文件,用户可能不会太高兴。因此,您不能my_malloc在生产程序中使用可能会丢失数据的简单技巧。但这对于不必担心此类事情的程序来说是一个巨大的便利。