Home > Net >  Is there a way to detect if a given header of the C Standard Library is included?
Is there a way to detect if a given header of the C Standard Library is included?

Time:02-11

More specifically, is it possible to detect, at compilation time, if a C standard header file is included (let say <complex>), and do that in a way that is cross-plateform and cross-compiler ? I'd like it to work with C 11 at least, but for the question's sake, is it possible for any C standard ?

I know the implementation of the C Standard Library is dependent on the compiler and operating system, but is there a standardized guard name for the header, a macro that I can check the existence of ?

I've run into this : Detect usage of STL in C , which is a hack not to use the headers, and this : Is there a way to detect portably that a standard header is included using macros?, which answers with a C 17 feature, and is in fact more about detecting a function.

What I want is to be able to write some preprocessor instruction at a given point in the code that will tell whether the header is included (yet). I checked the source code of (an implementation of) <complex> as an example, and _GLIBCXX_COMPLEX is defined, but probably only for this implementation.

CodePudding user response:

TL;DR : No, there is not, apart from the C 17 feature #if __has_include(<complex>). Not with defined macro anyway.

Long answer : there are two parts to the answer. What I read from some headers, and the tests I ran on differents OS with differents compilers.

Warning : I will write also about C, as some compilers uses the same macros. I also use the shortcut 'for C' and 'for C ' instead of 'when the header complex.h is included' and 'when the header <complex> is included'.

Ok, here's my best answer as for now.

About C and complex.h :

In C, the existence of the macro _Complex_I is the only macro that I think should be defined in any complex.h header, as it is specified by the ISO C99 (cf. ISO/IEC 9899:1999/TC3 text). The tests I ran shows that this is a realistic hypothesis. There are some additionnal macro used, such as _COMPLEX_H that seems to be defined when compiling with GCC, and _C_COMPLEX_T when compiling with MSVC. There might be others, I didn't find them, please don't hesitate to add them.

But it is C, not C , and one should not mix both.

About C and <complex> :

The C standard (ISO/CEI 14882:2011) does not specify such macro. In fact, it does not specify the inclusion of any macro (at first glance). It does specify the existence of the complex class however, but this does not answer the question. For what I read, _COMPLEX_ and _C_COMPLEX_T seems to be defined in the <complex> header for LLVM-clang and MSVC, but also in the complex.h for the apple implementation of the C math library (libm).
However, my tests with the LLVM-clang compiler on macOS failed showing those macro, and I can't find the file where I read that information. I also found that g is defining _GLIBCXX_COMPLEX.

If one wanted to do that with a C older than C 17, a solution would be to test with the given compilers and architectures the code will run onto. That is quite bad, but it's the closest answer I get.

The tests :

I give here the code that I run on the different OS, the compiler options, their version, and the results they prompt. _Complex_I was indeed defined for all C headers.
I wasn't able to run the test on macOS with GCC and G , but I bet that _Complex_I will be defined with GCC and _GLIBCXX_COMPLEX with G .

Tests for C

G -std=c 11 v9.3.0 on Ubuntu 20.04 : _GLIBCXX_COMPLEX

G -std=c 11 v11.2.0 on windows 10 (via Cygwin) : _GLIBCXX_COMPLEX

MSVC default c 11 option v14.29.xxxxx.x on windows 10 : _C_COMPLEX_T _COMPLEX_

Apple LLVM-clang -std=c 11 v10.0.1 : None (doesn't mean there is none, just that I don't know which one)

Code for C :

#include <iostream>
#include <complex>

int main(){

#ifdef _COMPLEX_
    std::cout << "_COMPLEX_" << std::endl;
#endif

#ifdef _C_COMPLEX_T
    std::cout << "_C_COMPLEX_T" << std::endl;
#endif

#ifdef _COMPLEX_H
    std::cout << "_COMPLEX_H" << std::endl;
#endif

#ifdef _Complex_I
    std::cout << "_Complex_I" << std::endl;
#endif

#ifdef _GLIBCXX_COMPLEX
    std::cout << "_GLIBCXX_COMPLEX" << std::endl;
#endif

    return 0;
}

Tests for C :

GCC -std=c99 v9.3.0 on Ubuntu 20.04 : _Complex_I _COMPLEX_H

GCC -std=c99 v11.2.0 on windows 10 (via Cygwin) : _Complex_I _COMPLEX_H

MSVC -std=c99 v14.29.xxxxx.x on windows 10 : _Complex_I _C_COMPLEX_T

Apple LLVM-clang -std=c99 v10.0.1 : _Complex_I

Code for C:

#include <stdlib.h>
#include <stdio.h>
#include <complex.h>

int main(){

#ifdef _COMPLEX_
    printf("_COMPLEX_\n");
#endif

#ifdef _C_COMPLEX_T
    printf("_C_COMPLEX_T\n");
#endif

#ifdef _COMPLEX_H
    printf("_COMPLEX_H\n");
#endif

#ifdef _Complex_I
    printf("_Complex_I\n");
#endif

#ifdef _GLIBCXX_COMPLEX
    printf("_GLIBCXX_COMPLEX\n");
#endif

    return 0;
}

To sum up :

MSVC is defining _C_COMPLEX_T whatever C or C used, and also _COMPLEX_ for C . _Complex_I is always defined for C, and G seems to define _GLIBCXX_COMPLEX whatever the plateform (test to be done on macOS) for C .

  • Related