C++标准不规定宏名,各编译器自行定义且版本间可能变动;可靠宏仅限__GNUC__、__clang_major__、_MSC_VER、__cplusplus等少数几个,其余须查文档并实测验证。

没有“完整版本对照表”这种东西——C++ 标准不规定宏名,各编译器自行定义,且同一编译器不同版本间也可能变动。你真正能依赖的,只有少数几个标准化程度高、广泛支持的宏,其余必须查文档、实测、加防御性判断。
哪些宏是相对靠谱、可直接用的
以下宏在 GCC、Clang、MSVC 主流版本中稳定存在,语义清晰,适合做基础平台/编译器识别:
-
__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__:GCC 及其兼容编译器(如 MinGW、ICC)提供,Clang 也定义但值为4、2、1(历史兼容,不代表真实版本) -
__clang_major__、__clang_minor__、__clang_patchlevel__:Clang 专属,准确反映 Clang 自身版本(不是它模拟的 GCC 版本) -
_MSC_VER:MSVC 唯一可靠版本标识,值为整数(如1930表示 VS2022 17.0),需查微软官方映射表,不能直接当主次版本拆分 -
__cplusplus:标准 C++ 版本标识(如201703L),注意它反映的是-std=设置,不是编译器能力上限
为什么不能靠 __VERSION__ 或字符串宏做自动化判断
__VERSION__ 是编译器自定义字符串(如 "13.2.0"、"Apple clang version 15.0.0 (clang-1500.1.0.2.5)"),不可解析、无格式保证,连空格和括号都可能变。曾有人试图用预处理器字符串化 + strcmp 比较,结果在 Clang 14 升 15 时因括号内空格变化直接失效。
更危险的是误信“隐含宏”:比如以为 __clang__ 存在就等于 Clang ≥ 12,但其实它从 Clang 2.9 就存在;又或者把 _MSC_FULL_VER 当通用字段,却不知它只在 MSVC 高版本(VS2015+)才稳定输出。
跨编译器判断的实用写法(带防错)
真正健壮的判断必须满足三点:明确目标(你要适配什么特性?)、分层检测(先编译器大类,再版本边界)、留退路(没匹配到就 fallback)。例如启用 [[likely]]:
#if defined(__clang__) # if __clang_major__ >= 13 # define ATTR_LIKELY [[likely]] # else # define ATTR_LIKELY __attribute__((hot)) # endif #elif defined(__GNUC__) # if __GNUC__ >= 12 # define ATTR_LIKELY [[likely]] # else # define ATTR_LIKELY __attribute__((hot)) # endif #elif defined(_MSC_VER) # if _MSC_VER >= 1930 // VS2022 17.0+ # define ATTR_LIKELY [[likely]] # else # define ATTR_LIKELY __declspec(hot) # endif #else # define ATTR_LIKELY #endif
关键点:[[likely]] 在 GCC 12+、Clang 13+、MSVC 1930+ 才真正稳定支持,低于此版本用等效替代,完全不支持时直接空定义——而不是硬塞一个未定义行为的宏。
查版本映射表时最容易忽略的细节
MSVC 的 _MSC_VER 和 Visual Studio 版本不是线性对应;GCC 的 __GNUC_PATCHLEVEL__ 在早期版本(如 4.8)可能为 0 但实际发布版有多个 patch;Clang 的 __clang_patchlevel__ 在 Apple Clang 中永远为 0(它只用 __apple_build_version__ 区分 Xcode 内部版本)。
最省事的做法:对每个目标编译器,只记 2–3 个关键分界点(如 Clang 12/13/14),其他版本统一按“已知最低支持版本”处理;所有判断逻辑必须配合 CI 实际跑多版本验证,光看文档会漏掉 patch 版本的 ABI 微调。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











