应组合使用编译器特有宏+两层字符串化宏+条件判断:GCC用__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__;Clang用__clang_major__、__clang_minor__、__clang_patchlevel__;MSVC从_MSC_FULL_VER提取主次补丁号,且检测顺序须为__clang__优先→__GNUC__次之→_MSC_VER最后。
如何用预定义宏获取 GCC/Clang/MSVC 的完整版本号
直接靠
或
等宏拼出“x.y.z”格式的完整版本号,不可靠——它们要么是字符串常量(如 GCC 的
是
,但 Clang 返回的是
),要么只提供主次版本(如 MSVC 的
是
,需查表换算)。真正可自动化、跨编译器提取“数字三段式版本”的方法,是组合使用宏 + 预处理器字符串化 + 条件判断。
关键点:不依赖运行时,纯编译期推导;所有逻辑必须在预处理器阶段完成,不能调用函数或 std::string。
GCC:优先用
、
、
,三者拼接最准(
含空格和前缀,解析易错)
Clang:必须用
、
、
;
不可直接拆分,因格式不固定(如 Apple Clang 会写
)
MSVC:
是唯一可靠入口,但它是整数,需映射:例如
(对应 VS 2022 17.11),实际补丁号需结合
(如
),再按千位拆解
预处理器字符串化技巧:把数字宏转为字面量字符串
想把
(值为
)变成字符串
,不能直接用
——这会被预处理器当作字面量字符串处理,结果是
而非
。必须用两层宏展开:
这样
展开后才是
。Clang 和 MSVC 同理,但 MSVC 需先从
提取补丁段:
立即学习
“
C++免费学习笔记(深入)
”;
→ 次版本(如
)
→ 构建号(通常忽略,或作为第三段)
更稳妥做法:直接用
推导主次版本,补丁号设为
,除非明确需要构建细节
常见错误:误判 Clang 兼容模式与 MSVC 混合宏
Clang 在 Windows 上常以
模式编译,此时它会同时定义
和
——若判断顺序写成 “先检查
再检查
”,就会把 Clang 误认为 MSVC。
C知道
CSDN推出的一款AI技术问答工具
下载
正确顺序必须是:先检测最特异的宏,再逐步回退:
优先检测
(Clang 独有)→ 再检测
(GCC/Clang 共有,但 Clang 已被上一步拦住)→ 最后检测
切勿用
判断 GCC:某些嵌入式 GCC 变种可能不定义
,但也不代表就是原生 GCC
MSVC 的
在 MinGW-w64 下不会定义,但 Clang + mingw-w64 会同时定义
和
,需注意交叉场景
版本对照表不能硬编码,得靠条件宏动态生成
所谓“全表”,不是真列几百行 Excel,而是用宏组合出可读、可比较的版本标识。比如定义:
这样
就是一个统一的整型版本号(如 GCC 13.2.0 →
,Clang 18.1.8 →
,MSVC 1941 →
),可用于
比较:
→ Clang ≥ 18.1.0 或 GCC ≥ 18.1.0(逻辑上成立,因数值可比)
但要注意:不同编译器的数值域不重叠,所以跨编译器比较仅适用于“是否足够新”的粗略判断,不能用于精确语义等价
真正的“对照汇总”应放在构建脚本或 CI 配置里,C++ 层只负责提供可计算的版本原子
最易被忽略的一点:
在旧 Clang(defined(__clang_patchlevel__) 做兜底,否则预处理失败。
__VERSION____GNUC____VERSION__"13.2.0""Clang 18.1.8"_MSC_VER1941__GNUC____GNUC_MINOR____GNUC_PATCHLEVEL____VERSION____clang_major____clang_minor____clang_patchlevel____VERSION__"Apple clang version 15.0.0 (clang-1500.0.40.1)"_MSC_VER1941 → 14.41.34120_MSC_FULL_VER194134120__GNUC_MINOR__2"2"#__GNUC_MINOR__"__GNUC_MINOR__""2"#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define GCC_VERSION_STR TOSTRING(__GNUC__) "." TOSTRING(__GNUC_MINOR__) "." TOSTRING(__GNUC_PATCHLEVEL__)GCC_VERSION_STR"13.2.0"_MSC_FULL_VER_MSC_FULL_VER / 100000 % 1000194134120 / 100000 % 1000 = 341_MSC_FULL_VER % 100000_MSC_VER0-fms-compatibility__clang___MSC_VER_MSC_VER__clang____clang____GNUC___MSC_VERdefined(__GNUC__) && !defined(__clang__)__clang___MSC_VER__clang____MINGW32__#define COMPILER_VERSION_INT ( \
(__clang__ ? (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) : \
(__GNUC__ ? (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) : \
(_MSC_VER * 100 + (_MSC_FULL_VER % 100000) / 100))) \
)COMPILER_VERSION_INT130200180108194100#if#if COMPILER_VERSION_INT >= 180100__clang_patchlevel__