Doc No: WG14 N1348
Date: 2008-11-19
Reply to:  Bill Seymour <[email protected]>

Support for Conditional Inclusion of Headers

Bill Seymour


Abstract

This paper suggests adding a mechanism for determining whether standard headers are available in the implementation. This can help users whose code needs to be portable to implementations of different versions of the Standard.

For example, with predefined macros:

    #ifdef __STDC_HAS_FOO__  // a new predefined macro for each header
      #include <foo.h>
      // ...
    #else
      // ...
    #endif

Or if we don’t mind adding a defined()-like operator to the preprocessor:

    #if available(<foo.h>)  // or just overload defined() itself
      #include <foo.h>
      // ...
    #else
      // ...
    #endif

Or even:

    #if include(<foo.h>)  // tries to #include <foo.h>
      // ...
    #else
      // ...
    #endif


Rationale

At present, it’s a fatal error if #include fails; and this can be a problem for users, particularly library authors, who want their code to be portable to C89/90/95 implementations but still be able to take advantage of C99 features (<stdint.h>, <complex.h>, etc.) when they’re available. This problem could get even bigger with C1X in the mix.

This can also be seen as a C++ compatibility issue because some C++0X implementors might well want to support some C1X features as extensions, just as some C++98 implementors did in fact support some of C99. Indeed, this paper was triggered because of the author’s desire to use <stdint.h> types, if available, in C++ code.

And note that this might also be useful in freestanding implementations that support some, but not all, of the standard headers required for hosted implementations (for example, <errno.h> but not <stdio.h>).

Feature-test macros in the headers are clearly no help with this particular problem because you have to include the header to get the macro; and __STDC_VERSION__ isn’t a clue unless the implementation is fully conforming. (For example, some version of gcc might have what I want; but it can’t set __STDC_VERSION__ to the required value because it doesn’t have everything yet.)

Solving this problem today requires either having different versions of your code for different implementations or testing version numbers for every possible implementation of the standard library to which you might want to port your code. (For an example of the latter in C++, have a look at all the hoops that Boost jumps through.)

The author believes that either new predefined feature-test macros or a small change to the preprocessor would be a big help to users who need to support implementations conforming to different versions of the Standard.