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 .