通常,一个测试malloc
的结果是否不是NULL
才能知道内存分配是否成功。通过一系列malloc
调用,这将成为冗长或繁琐的比较。
相反,可以在一系列errno = 0
调用的顶部设置malloc
,然后在末尾测试errno == ENOMEM
吗?
这假定如果任何分配失败,则程序或函数将无法继续进行,而必须返回/退出。它还假定malloc
调用是连续的和连续的,并且根据手册,malloc
只能将errno
设置为ENOMEM
。
示例如下所示:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#define N (1 << 20)
int main()
{
double *a = NULL;
double *b = NULL;
double *c = NULL;
errno = 0;
a = malloc(N * sizeof *a);
b = malloc(N * sizeof *b);
c = malloc(N * sizeof *c);
if (errno == ENOMEM) {
perror(NULL);
free(a);
free(b);
free(c);
return EXIT_FAILURE;
}
errno = 0;
/* Do interesting stuff */
free(a);
free(b);
free(c);
return EXIT_SUCCESS;
}
(该示例使用main()
,但它也可能是另一个无法运行的功能,但是程序可能会继续执行,并且实际上不会退出程序,因此{{1} }通话是必需的。)
我看不出为什么不能安全地完成此操作的任何原因,但这不是我遇到的惯用语,因此是个问题。
答案 0 :(得分:2)
不,您不能安全地以便携式方式执行此操作。
按照C标准的7.5 Errors <errno.h>
, paragraph 3:
程序启动时,初始线程中
errno
的值为零(其他线程中errno的初始值为不确定的值),但是任何库函数都不会将其设置为零。 可以通过库函数调用将errno
的值设置为非零,前提是在描述中未记录errno
的使用。在此国际标准中起作用。
由于malloc()
并未被C标准设置为errno
,因此可以自由地errno
争取成功。
答案 1 :(得分:1)
相反,可以在一系列malloc调用的顶部设置errno = 0,然后在最后测试errno == ENOMEM吗?
是的,只要记录到您对malloc
的实现将errno
设置为ENOMEM
即可。 C11标准(第7.22.3.4节)中的规范仅提到返回的指针将是NULL
,而不是将设置errno
,因此从技术上讲,您的代码不可移植。
在MacOS,Windows和Linux中,malloc
的默认实现确实设置了errno
,因此世界上大多数计算机都在使用。但是,如果需要真正的可移植性,请最后写
if (a == NULL || b == NULL || c == NULL)
{
// Handle the failure
}
附录:errno
之后,无需将malloc
重置为零。