有没有办法检测是否包含C++标准库的给定标头?



更具体地说,是否可以在编译时检测是否包含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 上完成的测试)。

最新更新