简体   繁体   中英

Test errno for ENOMEM, instead of comparing a series of malloc calls to NULL

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 of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM