3
\$\begingroup\$

The Standard C Library consists of various headers files. Often only a few select ones are needed for given code.

Other times it is simply convenient coding to include them all in a .c file, even if that make the compilation time a bit slower.

Including all standard <*.h> is useful to help detect naming collisions of a .c file with an existing standard function, object, type, macro, etc.

Review Goal

How well does std.h accomplish the goal of including all standard header files via one .h file given that the set varies amongst C versions and implementations?

/*
 * std.h
 *  Created on: Mar 16, 2019, Author: chux
 */

#ifndef STD_H_
#define STD_H_

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#if defined __STDC__ && defined __STDC_VERSION__

#if __STDC_VERSION__ >= 199409
#include <iso646.h>
#include <wchar.h>
#include <wctype.h>
#endif

#if __STDC_VERSION__ >= 199901
#ifndef __STDC_NO_COMPLEX__
#include <complex.h>
#endif
#include <fenv.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <tgmath.h>
#endif

#if __STDC_VERSION__ >= 201112
#include <stdalign.h>
#ifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#endif
#include <stdnoreturn.h>
#ifndef __STDC_NO_THREADS__
#include <threads.h>
#endif
#include <uchar.h>
#endif

#if __STDC_VERSION__ >= 201710
/* None added */
#endif

#endif

#endif /* STD_H_ */

In making a set of functions and types called say foo, I do not recommend including all header files in a foo.h, yet perhaps in foo.c.

Sample usage

// foo.h  (no std.h here)
#ifndef FOO_H_
#define FOO_H_

#include <stdint.h>
#include <time.h>

typedef struct {
    time_t t;
    uint32_t u32;
} foo;

void foo_this(foo *f);
void foo_that(foo *f);

#endif /* FOO_H_ */

foo.c or main.c

#include "foo.h"
#include "std.h"

int main(void) {
  foo f;
  foo_this(&f);
  foo_that(&f);
  printf("Hello World!\n");
  return 0;
}

The alternative spellings afforded in <iso646.h> seem to be a solution to a regional character set problem of years ago. I reluctantly included <iso646.h> here but do see that a good candidate to exclude. It defines macros for and, or, xor and others.

\$\endgroup\$
  • \$\begingroup\$ When I read the title, I thought "but why?" Having read the description, I see what you're doing. However, beware that that if you contravene the naming rules - which I'm sure you don't - then finding no collisions using this compiler, today doesn't guarantee anything about other builds. Past success is no guarantee of future performance! \$\endgroup\$ – Toby Speight Mar 25 at 11:58
  • \$\begingroup\$ @TobySpeight Agree the including all <*.h> will not certainly detect all name collision and future ones, yet is a reasonable test today to potential discern them. \$\endgroup\$ – chux Mar 25 at 12:23
3
\$\begingroup\$
  • Your code doesn't cover "freestanding implementations" (embedded systems or OS). You could check for #if __STDC_HOSTED__ == 0 and reduce the headers. Freestanding implementations need not provide all headers except a minimal subset, see C11 4/6:

    A conforming freestanding implementation shall accept any strictly conforming program in which the use of the features specified in the library clause (clause 7) is confined to the contents of the standard headers <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, and <stdnoreturn.h>

    Though of course freestanding implementations may provide other headers too, making this hard to fulfil without a specific implementation in mind.

  • Style issue: you should indent everything within #if... #endif just as you would for regular if statements. It is also good practice to leave a comment /* */ after each #endif to document which #if is belongs to.

EDIT: proposed indention fix

#ifndef STD_H_
#define STD_H_

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#if defined __STDC__ && defined __STDC_VERSION__

  #if __STDC_VERSION__ >= 199409
    #include <iso646.h>
    #include <wchar.h>
    #include <wctype.h>
  #endif

  #if __STDC_VERSION__ >= 199901
    #ifndef __STDC_NO_COMPLEX__
      #include <complex.h>
    #endif
    #include <fenv.h>
    #include <inttypes.h>
    #include <stdbool.h>
    #include <stdint.h>
    #include <tgmath.h>
  #endif

  #if __STDC_VERSION__ >= 201112
    #include <stdalign.h>
    #ifndef __STDC_NO_ATOMICS__
      #include <stdatomic.h>
    #endif
    #include <stdnoreturn.h>
    #ifndef __STDC_NO_THREADS__
      #include <threads.h>
    #endif
    #include <uchar.h>
  #endif

  #if __STDC_VERSION__ >= 201710
    /* None added */
  #endif

#endif /* #if defined __STDC__ && defined __STDC_VERSION__ */

#endif /* STD_H_ */
\$\endgroup\$
  • \$\begingroup\$ Please post a sample # indent. I have tried various styles, ` #if bar` (my auto formatter (Eclipse) keeps shifting them left ) and # if bar which looks odd. Perhaps you have another? \$\endgroup\$ – chux Mar 25 at 13:29
  • 1
    \$\begingroup\$ @chux Posted. After trying some 30+ different, magic IDEs including GNU indent, I'm convinced that mankind will never develop intelligent AI. So I tend to fall back to good ole spacebar :) \$\endgroup\$ – Lundin Mar 25 at 14:10
  • \$\begingroup\$ Thanks for the __STDC_HOSTED__ idea. I'll need to dig deeper into that. \$\endgroup\$ – chux Aug 3 at 15:11
3
\$\begingroup\$

With this suggested usage:

#include "foo.h"
#include "std.h"

then any macros defined in "std.h" (and not used in the rest of the main) won't break the program. Swapping these round:

#include "std.h"
#include "foo.h"

solves that problem, but then fails to diagnose missing includes in "foo.h".

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.