第3.15章: 特性测试

English

什么是特性测试

不同的编译器、平台和标准库支持不同的特性。 特性测试让你的程序可以在编译期适配当前可用的东西。

所有特性测试都由预处理器完成,发生在编译器 看到你的代码之前。

检测头文件:__has_include

__has_include 在包含之前检查头文件是否存在。


#if __has_include()
#include 
#else
println("std::span not available");
#endif

检测 #embed:__has_embed

__has_embed 检查编译器是否支持 #embed 指令。


#if __has_embed("resource.bin")
static constexpr auto data =
#embed "resource.bin";
#else
print("embed not supported\n");
#endif

检测 C++ 标准版本:__cplusplus

宏 __cplusplus 指明编译器正在使用哪个 C++ 标准。


#if __cplusplus >= 202002L
print("C++20 or later\n");
#elif __cplusplus >= 201703L
print("C++17\n");
#else
print("older C++\n");
#endif

这个宏由编译器定义,而不是标准库。

编译器特性宏

编译器定义了若干宏,用来指明某些语言特性是否启用。

__cpp_exceptions

若启用了异常处理,则该宏已定义。


#ifdef __cpp_exceptions
print("exceptions enabled\n");
#else
print("exceptions disabled\n");
#endif

由于实现复杂度或运行时开销,许多环境完全禁用异常 ——包括 Android、WebAssembly、嵌入式系统以及操作系统内核。 我们将在后续章节中详细讨论这一点。

__cpp_rtti

若启用了运行时类型信息(RTTI),则该宏已定义。


#ifdef __cpp_rtti
print("RTTI enabled\n");
#else
print("RTTI disabled\n");
#endif

平台检测

编译器定义了若干用于识别操作系统的宏。


#ifdef _WIN32
print("Windows\n");
#endif

#ifdef __linux__
print("Linux\n");
#endif

#ifdef __APPLE__
print("macOS\n");
#endif

编译器检测


#ifdef __clang__
print("Clang\n");
#endif

#ifdef __GNUC__
print("GCC\n");
#endif

#ifdef _MSC_VER
print("MSVC\n");
#endif

检测库特性:<version> 头文件

C++ 标准库提供了形如 __cpp_feature 的特性测试宏。 这些宏指明哪些库特性可用。

它们全都定义在 <version> 头文件中。


#include 

#ifdef __cpp_lib_span
print("std::span available\n");
#else
print("std::span not available\n");
#endif

特性测试宏的完整权威列表见:

https://en.cppreference.com/w/cpp/feature_test.html

检测 C 宏:features.h

你的工具链还提供了许多 C 层特性宏。它们并不是 C++ 的一部分,但会影响可移植性与底层行为。

它们通常定义在一个名为:


features.h

的头文件中。该头文件属于你的 C 库实现(glibc、musl、BSD libc 等)。它包含这样的宏:

这些宏控制哪些 C 与 POSIX API 可用。 确切列表请查看你工具链的 features.h。

要点