Is it required to include <errno.h> to use perror?

115 Views Asked by At

I can print the human-readable version of errno using perror like this:

#include <errno.h>
#include <stdio.h>

int main(void) {
    FILE *fp = fopen("file.txt", "r");
    if (fp == NULL) {
        perror("Unable to open file");
        return -1;
    }

    fclose(fp);
    return 0;
}

This also works on my implementation:

#include <stdio.h>

int main(void) {
    FILE *fp = fopen("file.txt", "r");
    if (fp == NULL) {
        perror("Unable to open file");
        return -1;
    }

    fclose(fp);
    return 0;
}

Is using perror without including <errno.h> nonstandard?

2

There are 2 best solutions below

0
dbush On BEST ANSWER

Yes, it is allowed to use perror without including errno.h. Section 7.21.10.4p1 of the C standard gives the following synopsis of this function:

#include <stdio.h>
void perror(const char *s);

Including errno.h is only required to access the errno macro.

0
John Bollinger On

Is using perror without including <errno.h> standard?

Yes.

I presume you mean a direct call, of the form

perror("context label");

... as other means, such as calling the function via a function pointer provided externally, have even less reason to require any headers.

The (only) formal constraints on function-call expressions are:

The expression that denotes the called function shall have type pointer to function returning void or returning a complete object type other than an array type.

The number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter

(C23 6.5.2.2/1-2)

There has not for a long time been any implicit typing in C, so for a function call via the function's identifier, the first constraint requires an in-scope declaration of the identifier. Before C23, the second constraint was provisional on that declaration providing a prototype, but C23 will not allow function types that do not include prototypes.

Note well, however, that although the spec requires the function pointer through which the function is called to have a type compatible with the function definition (6.5.2.2/7), it nowhere requires its declaration to be drawn from a header. Header files are a convenience, not a requirement.

Of course, that leads us to the question of which header(s) in fact provide a definition of perror()? The language spec says that stdio.h does (C23 7.23.10.4). That does not preclude other headers from providing the declaration as well, of course, but if you don't declare perror() yourself (and you shouldn't) then #including stdio.h is sufficient to get its declaration.

And that's all the header you need. The perror() function is not implemented by the compilation unit from which you call it, so it has no visibility on and cannot be affected by any declarations in scope at the point of the call, except as already discussed. In particular, the errno variable itself exists, and has static storage duration and external linkage, whether any of your translation units include errno.h or not. You do not need to include errno.h for standard library functions to set or read that variable.

Section 6.5.2.2 of the spec gives some other semantic rules around function calls as well, but none of them bear on header inclusion.