更具体地说,是否可以在编译时检测是否包含C++标准头文件(假设<complex>
),并以跨平台形式和交叉编译器的方式执行此操作?我希望它至少适用于 C++11,但为了这个问题的缘故,是否有任何C++标准?
我知道C++标准库的实现取决于编译器和操作系统,但是标头是否有标准化的守卫名称,我可以检查是否存在的宏?
我遇到了这个:检测 STL 在 C++ 中的使用情况,这是不使用标头的黑客,并且这个:有没有办法使用宏直观地检测标准标头是否包含?,它以 C++17 功能回答,实际上更多的是关于检测功能。
我想要的是能够在代码中的给定点编写一些预处理器指令,以判断是否包含标头(尚未)。我检查了<complex>
的源代码作为示例,并定义了_GLIBCXX_COMPLEX
,但可能仅适用于此实现。
TL;DR:不,除了 C++17 功能#if __has_include(<complex>)
之外,没有。无论如何,没有定义的宏。
长答案:答案有两个部分。我从一些标头中读取的内容,以及我在具有不同编译器的不同操作系统上运行的测试。
警告:我也会写关于C的文章,因为一些编译器使用相同的宏。我还使用快捷方式"for C"和"for C++",而不是"当包含标头complex.h
时"和"当包含标头<complex>
时"。
好的,这是我目前的最佳答案。
关于 C 和complex.h
:
在C中,宏的存在_Complex_I
是我认为应该在任何complex.h
标题中定义的唯一宏,因为它是由ISO C99(参见.ISO/IEC 9899:1999/TC3文本指定的)。我运行的测试表明这是一个现实的假设。使用了一些额外的宏,例如在使用 GCC 编译时似乎定义的_COMPLEX_H
, 以及使用 MSVC 编译时的_C_COMPLEX_T
。可能还有其他的,我没有找到它们,请不要犹豫,添加它们。
但它是C,而不是C++,不应该同时使用两者。
关于C++和<complex>
:
C++标准(ISO/CEI 14882:2011)没有指定此类宏。实际上,它没有指定包含任何宏(乍一看)。 但是,它确实指定了complex
类的存在,但这并不能回答这个问题。 对于我所读到的内容,_COMPLEX_
和_C_COMPLEX_T
似乎在<complex>
标题中定义 LLVM-clang 和 MSVC,但也在苹果实现 C 数学库 (libm) 的complex.h
。
但是,我在macOS上使用LLVM-clang编译器进行的测试未能显示这些宏,并且我找不到读取该信息的文件。 我还发现 g++ 正在定义_GLIBCXX_COMPLEX
。
如果要使用早于 C++17 的C++来执行此操作,解决方案是使用代码将运行的给定编译器和体系结构进行测试。 这很糟糕,但这是我得到的最接近的答案。
测试:
我在这里给出了我在不同操作系统上运行的代码、编译器选项、它们的版本以及它们提示的结果。_Complex_I
确实为所有 C 标头定义了。
我无法使用GCC和G ++在macOS上运行测试,但我敢打赌_Complex_I
将使用GCC定义,_GLIBCXX_COMPLEX
使用G ++定义。
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 默认 c++11 选项 v14.29.xxxxx.x 在 Windows 10 上:_C_COMPLEX_T
_COMPLEX_
Apple LLVM-clang -std=c++11 v10.0.1 : 无(并不意味着没有,只是我不知道是哪一个)
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;
}
C 语言的测试 :
GCC -std=c99 v9.3.0 on Ubuntu 20.04 :_Complex_I
_COMPLEX_H
GCC -std=c99 v11.2.0 在 Windows 10 上 (通过 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
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_Tn");
#endif
#ifdef _COMPLEX_H
printf("_COMPLEX_Hn");
#endif
#ifdef _Complex_I
printf("_Complex_In");
#endif
#ifdef _GLIBCXX_COMPLEX
printf("_GLIBCXX_COMPLEXn");
#endif
return 0;
}
总结一下:
MSVC 正在定义_C_COMPLEX_T
所使用的任何 C 或C++,并且也_COMPLEX_
用于C++。_Complex_I
总是为 C 定义,而 G++ 似乎_GLIBCXX_COMPLEX
定义C++的任何平台形式(在 macOS 上完成的测试)。