Question Details

No question body available.

Tags

c++ c language-lawyer c-preprocessor

Answers (3)

December 19, 2025 Score: 7 Rep: 71,050 Quality: High Completeness: 60%

If you want to have a macro to use in place of hasinclude on systems that do not support it, and still follow the letter of the quoted piece of the standard, you should be able to use pasting.

#ifndef
has
include #define HASINCLUDE(Arg) 0 #warning no "has include" #else #define HASINCLUDE(Arg) ## hasinclude(Arg) #endif

#if HASINCLUDE() #include #else #include "backup-header.h" #endif


If you perform the same kind of complicated conditional checks that are needed to see if you want to include a particular header file, that only vary by what headers you are checking for, you can hide those checks in a generic wrapper header. This abstracts the hasinclude logic away so that the difficult construction of the checks is only done once and lives in a single file.

/* wrap-boiler-plate.h */ /* NB: No pragma once, since this file is generic */ #ifdef has
include #if hasinclude(MYHEADER) #include MYHEADER #define HASINCLUDEHEADERH #endif #endif

#ifndef HASINCLUDEHEADERH #include MYBACKUPHEADER #endif

#undef HASINCLUDEHEADERH

#undef MYHEADER #undef MYBACKUPHEADER

Then, you have a wrapper header file instance that uses the generic one, which would name the header being tested and the backup:

/* wrapped-header.h */ #pragma once #define MY
HEADER #define MYBACKUPHEADER "backup-header.h" #include "wrap-boiler-plate.h"
December 20, 2025 Score: 0 Rep: 16,554 Quality: Low Completeness: 50%

If you're not in a library's public headers (where you have to worry about interfering with uncontrolled files including you), you can just do:

#ifndef hasinclude
#define hasinclude(x) 0
#endif

(There is some debate over whether it's legal to redefine builtins inside non-taken #if blocks; if you have a compiler that actually cares, you can always move it to a different file.)

You can use a more advanced version that defers to individual macros (which might be individually defined as 0 or 1 depending on what you can guess should be available, or generated by a configure script, etc.):

#ifndef hasinclude

define hasinclude(x) hasinclude ## x

#endif

#define BOGUS

#define
hasincludeBOGUS 1

#if has_include(BOGUS) #error "you have a " #else #error "you do not have a " #endif
December 19, 2025 Score: -1 Rep: 15,572 Quality: Medium Completeness: 80%

My preference is to define my own compatibility macros (or static inline functions) that do not have reserved names.

GCC already supports short-circuiting conditionals, for example (simplified):

#if defined(hascppattribute) && hascppattribute(gnu::musttail)

define MUSTTAIL [[gnu::musttail]]

#elif defined(has
cattribute) && hascattribute(gnu::musttail)

define MUSTTAIL [[gnu::musttail]]

#elif defined(has
attribute) && hasattribute(musttail)

define MUSTTAIL attribute((musttail))

#else

define MUSTTAIL //

#endif

This lets you flatten conditionals like this one, and it doesn’t break anything. Compilers ought to support this extension and the next versions of the C and C++ standards really should make it official.

Since I do have to support compilers that don’t allow this (or throw a diagnostic), what I currently have in my common first header is:

#if defined(hascppattribute)

if hascppattribute(clang::musttail)

define MUSTTAIL [[clang::musttail]]

elif hascppattribute(gnu::musttail)

define MUSTTAIL [[gnu::musttail]]

endif // C++11 or later

#elif defined(
hascattribute)

if hascattribute(clang::musttail)

define MUSTTAIL [[clang::musttail]]

elif hascppattribute(gnu::musttail)

define MUSTTAIL [[gnu::musttail]]

endif // C23 or later

#endif

#ifndef MUSTTAIL

if ((defined(GNUC) && GNUC >= 15) || \

(defined(clang) && clangmajor >= 13) || \ (defined(INTELLLVMCOMPILER) && INTELLLVMCOMPILER >= 20210400)) // The last clause is unnecessary, since ICX defines clang >= 13.

define MUSTTAIL attribute((musttail))

endif // Clang, ICX, ICPX or GCC with standard attributes disabled.

#endif

#ifndef MUSTTAIL

define MUSTTAIL //

#endif // Did not detect support: define as whitespace.

Similarly, if I need to write portable code that aligns a pointer upward to the next aligned address, I’ll write a wrapper for it and then an implementation for each platform I need to support that calls std::align on C++11, builtinalignup on Clang, casts to uintptrt, or whatever else is appropriate.

In this use case, you would preferably have the #ifndef blocks like the second section look for a macro that would be defined if and only if the header had been included. There might be an appropriate one in the header already. Otherwise, I would fall back on nested conditionals like in the first section above (#ifdef
hasinclude around a bunch of #elif hasinclude("bar.h") blocks). Currently, some of my projects check cplusplus and include either , , etc., or else and with using declarations. This guarantees that sizet is properly declared, and also std::sizet on C++, no matter which headers any other library I bring in includes.

Another option here is to write a wrapper around one of the functions you care about and use that as your condition. This macro can even have the same name as the function.

#ifdef HASSTRNCMPI
// Ensure that strncmpi is also declared as a macro, for later tests.

define strncmpi(s1, s2, n) strncmpi((s1), (s2), (n))

#endif

#if !defined(strncmpi) && defined(WIN32)

include // Use the Windows equivalent.

define strncmpi(s1, s2, n) StrCmpNIA((s1), (s2), (n))

#endif

#if !defined(strncmpi) && defined(
hasinclude)

if hasinclude() // Use the POSIX equivalent from BSD.

include

define strncmpi(s1, s2, n) strncasecmp((s1), (s2), (n))

endif

#endif