Normally, one tests for the result of malloc
to not be NULL
to known whether memory allocation succeeded. With a series of malloc
calls, this becomes a lengthy or tedious set of comparisons.
Instead, could one set errno = 0
at the top of the series of malloc
calls, and then test for errno == ENOMEM
at the end?
This assumes if any allocation fails, the program or function can't proceed and has to return/bail out. It also assumes the malloc
calls are sequential and continuous, and that, as per the manual, malloc
can only set errno
to ENOMEM
.
An example would be something like the following code:
#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;
}
(The example uses main()
, but it could also be another function that simply can't be run, but the program might proceed otherwise, and no actual exit from the program happens, and the free()
calls are necessary.)
I don't see any reason why this can't be done safely, but it's not an idiom I have come across, hence the question.
No, you can not safely do this in a portable manner.
Per 7.5 Errors <errno.h>
, paragraph 3 of the C standard:
The value of
errno
in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function. The value oferrno
may be set to nonzero by a library function call whether or not there is an error, provided the use oferrno
is not documented in the description of the function in this International Standard.
Since malloc()
is not documented to set errno
by the C standard, it's free to munge errno
on success.
Instead, could one set errno = 0 at the top of the series of malloc calls, and then test for errno == ENOMEM at the end?
Yes you could as long as your implementation of malloc
is documented to set errno
to ENOMEM
. The specification in the C11 standard (§ 7.22.3.4) only mentions that the pointer returned will be NULL
, not that errno
will be set, so your code is technically not portable.
The default implementation of malloc
in macOS, Windows and in Linux does set errno
so that's most of the computers in the World covered. However, if true portability is required, at the end just write
if (a == NULL || b == NULL || c == NULL)
{
// Handle the failure
}
Addendum: There's no need to reset errno
back to zero after the malloc
s.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.