应组合编译器专属宏生成整型版本码:gcc用__gnuc__、__gnuc_minor__、__gnuc_patchlevel__;clang需区分apple/llvm并用__clang_major__等;msvc须用__msc_full_ver拆解,不可单靠__msc_ver换算。

如何用预定义宏获取 GCC/Clang/MSVC 的完整版本号
直接靠 __VERSION__ 或 __GNUC__ 等宏拼出「x.y.z」格式的完整版本号,不可靠——它们要么是字符串常量(如 GCC 的 __VERSION__ 含空格和括号),要么只暴露主次版本(如 _MSC_VER 是整数,需手动拆解)。真正可自动化、可比较、可嵌入构建逻辑的方案,是组合使用编译器专属宏 + 预处理器算术展开。
- GCC:用
__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__三者拼接,例如(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)得到整型版本码(如 GCC 12.3.0 → 120300) - Clang:必须同时检查
__clang__和__apple_build_version__(Apple Clang)或__clang_major__(LLVM Clang),因为 Apple Clang 的__clang_version__是字符串,而 LLVM Clang 的__clang_major__等才是可用整数 - MSVC:
_MSC_VER是核心,但需注意:1930 表示 VS2022 17.3,不是 19.3;真实映射需查表,不能简单除10或取小数位
MSVC _MSC_VER 到语义化版本(如 17.4.0)的准确换算规则
_MSC_VER 是整数,但微软从 VS2015(_MSC_VER == 1900)起就不再与“主版本号.次版本号”对齐。它本质是编译器内部代号,必须查官方对照表才能转成用户理解的 VS 版本和完整工具链版本(含 _MSC_FULL_VER)。
-
_MSC_VER == 1930→ VS2022 17.3.x(对应_MSC_FULL_VER == 193030705表示 17.3.30705) -
_MSC_VER == 1940→ VS2022 17.10.x(注意:17.10 不是 17.1,VS 17.10 是正式版,不是预览版) - 可靠做法:用
_MSC_FULL_VER拆解 —— 前四位是_MSC_VER,后五位是 build 号,完整版本 =_MSC_VER / 100._MSC_VER % 100._MSC_FULL_VER % 100000(仅适用于 VS2015+)
跨编译器统一版本号整型编码的实用宏封装
为避免重复判断,建议在项目头文件中定义一个统一的 COMPILER_VERSION 整型宏,确保所有编译器下都输出形如 120300(GCC 12.3.0)、150000(Clang 15.0.0)、193000(MSVC VS2022 17.3,忽略 patch)的值,便于 #if COMPILER_VERSION >= 194000 这类条件编译。
#if defined(_MSC_VER)
#define COMPILER_VERSION (_MSC_VER * 1000)
#elif defined(__clang__)
#if defined(__apple_build_version__)
// Apple Clang: use __clang_major__, __clang_minor__, __clang_patchlevel__
#define COMPILER_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#else
#define COMPILER_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#endif
#elif defined(__GNUC__)
#define COMPILER_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif
注意:__clang_patchlevel__ 在旧版 Clang(#ifdef 保护或默认为 0。
常见陷阱:__VERSION__ 字符串无法用于预处理器条件判断
很多人想用 #if __VERSION__ >= "12.3.0",这是错的——__VERSION__ 是字符串字面量,预处理器不支持字符串比较,且该宏内容不稳定(GCC 输出 "12.3.0 (Ubuntu 12.3.0-1ubuntu1~22.04)",Clang 输出 "Ubuntu Clang 15.0.7"),连空格位置都不一致。
- 永远不要在
#if中使用任何字符串宏 -
__VERSION__只适合运行时日志打印,不适合编译期分支 - Clang 的
__clang_version__同样是字符串,同样不可用于#if - 若真需运行时显示友好版本,可用
std::string_view包装__VERSION__,但别试图解析它
最易被忽略的一点:不同发行版对同一 GCC 版本打的补丁号(patchlevel)可能不同,__GNUC_PATCHLEVEL__ 在 Ubuntu、CentOS、Alpine 上未必一致,做 ABI 兼容判断时应优先依赖主次版本,而非完整三段式版本号。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











