May a header from the C standard library include another header?

519 Views Asked by At

I dimly remember a rule that "No header of the C standard library shall include any other header of the C standard library, except where specifically allowed". But curiously, I couldn't find such a rule written down in C11. I would have expected it in 7.1.2 "Standard headers".

  • Is there such a rule in C?
  • Is there such a rule in POSIX?
  • Is there such a rule in any other standard?
3

There are 3 best solutions below

0
On

I dimly remember a rule that "No header of the C standard library shall include any other header of the C standard library, except where specifically allowed".

There is no such rule in the C language specification or the POSIX standards. Both of these, especially the first, steer well clear of specifying implementation details such as this. They describe positive structure and semantics that users can rely on, but generally do not constrain implementations to avoid specific structures or details.

For the most part, the standards also do not specify that any particular headers do include other header, so, as a matter of style and portability, it is wise to write code as if no standard header included any other. More generally, this leads toward a common style guideling that each source file you write, including headers, should, for each identifier used, either declare that identifier appropriately itself or #include a header documented to declare it.

However, as @chqrlie points out in their answer, the standard explicitly specifies that certain standard library headers include specific other standard library headers.

But curiously, I couldn't find such a rule written down in C11. I would have expected it in 7.1.2 "Standard headers".

That is indeed where one would look in C11. As you say, it expresses no rule having the effect you describe.

Is there such a rule in C?

No, and that would be inconsistent with other provisions, as described above. Furthermore, in some putatively conforming C implementations, more of the standard headers than those @chqrlie points out do #include other standard library headers.

Is there such a rule in POSIX?

No, and that would be inconsistent with other provisions, as described above. Furthermore, in some putatively POSIX-conforming C implementations, more standard headers than those @chqrlie points out do #include other standard library headers.

Is there such a rule in any other standard?

I am unaware of any other standard that speaks to the C standard library. There is a wide variety of code conventions, and it is conceivable that one or more have such a rule about writing program and library headers, but the standard library is not within the scope of such conventions. Obviously, however, no one can speak authoritatively about the universe of all standards.

It is perhaps relevant also to raise paragraph 7.1.2/4 of C11, which says, in part:

Standard headers may be included in any order; each may be included more than once in a given scope, with no effect different from being included only once, except [caveat regarding assert.h; ...]. However, if an identifier is declared or defined in more than one header, the second and subsequent associated headers may be included after the initial reference to the identifier.

The C language specification explicitly disclaims any requirement that the standard library headers be implemented as ordinary source files expressed in the C language, but do note that to the extent that a particular implementation provides such a representation, that explicitly raises the possibility that some identifiers may be declared or defined by multiple headers. Although it is not guaranteed to happen, and there are other ways that could arise, it is consistent with some headers including others.

0
On

Searching the C Standards from Ansi-C (C90) up to the latest draft, and further scanning historic references such as Unix V7 manuals and the K&R books, I could not find a reference to this rule.

The contents, location and implementation of standard header is implementation specific, some types and macros are defined in multiple headers, so a consistent scheme to avoid redefinition warnings is necessary, and is implemented via conditional inclusion in common C library implementations.

Some systems headers are specifically specified as including other headers:

7.25 Type-generic math <tgmath.h>

The header <tgmath.h> includes the headers <math.h> and <complex.h> and defines several type-generic macros.

7.26 Threads <threads.h>
7.26.1 Introduction
The header <threads.h> includes the header <time.h>, defines macros, and declares types, enumeration constants, and functions that support multiple threads of execution.

Some standard POSIX headers are also documented as including other system headers.

Unless a programmer is implementing the C library, the rule would make no difference anyway: system headers documented as defining a standard type, enumeration constant, macro, function or variable should be included before this identifier is used. System headers can be included in any order, multiple inclusion should not cause any problem.

2
On

As far as I could see, it is not stated explicitly as permissible (or not). But I believe the possibility is implied by the following passage

7.1.2 Standard headers (emphasis mine)

4 If used, a header shall be included outside of any external declaration or definition, and it shall first be included before the first reference to any of the functions or objects it declares, or to any of the types or macros it defines.

When we cross reference this "shall" requirement against its meaning in the conformance section

4. Conformance

2 If a "shall" or "shall not" requirement that appears outside of a constraint or runtime- constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words "undefined behavior" or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe "behavior that is undefined".

So if one were to call the abs function without including stdlib.h, the behavior would be undefined. Undefined behavior by its very nature includes the possibility of things "working". And so, if another standard header includes stdlib.h and the program "works", this is inline with the contract stated above.