唯一可靠方式是通过预定义宏识别编译器及版本:__gnuc__等对应gcc,_msc_ver对应msvc,__clang_major__等对应clang,apple clang需优先检查__apple_build_version__,且须注意交叉编译和构建系统干扰。

如何用预定义宏识别编译器及其版本号
直接看 __GNUC__、_MSC_VER、__clang_major__ 这类宏,是唯一可靠方式——它们由编译器自身注入,不依赖外部工具或运行时检测。
注意:不能靠 __linux__ 或 _WIN32 判断编译器,这些只反映目标平台;也不能靠 __VERSION__ 字符串解析,它格式不统一(GCC 输出 "11.4.0",Clang 是 "16.0.6 (https://github.com/llvm/llvm-project.git 851e7d7..."),极易出错。
-
__GNUC__+__GNUC_MINOR__+__GNUC_PATCHLEVEL__:GCC 真实版本,如 GCC 12.2.1 →__GNUC__ == 12 -
_MSC_VER:MSVC 版本编码,不是直观数字。VS 2022 17.4 对应_MSC_VER == 1934,查表才知含义 -
__clang_major__等三组宏:Clang 自身版本(非 LLVM 版本),与 GCC 兼容模式无关 -
__INTEL_COMPILER和__INTEL_COMPILER_UPDATE:ICC/ICPC,但新版 ICX(基于 Clang)已改用 Clang 宏
常见编译器版本宏对照表(截止 2024 年主流版本)
以下数值来自真实编译器输出验证,非文档推测。重点标出易混淆点:
- MSVC:
_MSC_VER == 1930→ VS 2022 17.0;1933→ 17.3;1934→ 17.4;1935→ 17.5;1936→ 17.6 - GCC:
__GNUC__ == 11覆盖 11.1–11.4;__GNUC__ == 12覆盖 12.1–12.3;无单独宏区分 patch 版本 - Clang:
__clang_major__ == 15对应 Clang 15.0.x;16对应 16.0.x;Clang 17 开始支持 C++23std::expected,可用此宏条件编译 - Apple Clang:
__apple_build_version__是关键,例如值14030022表示 Xcode 14.3.1;仅靠__clang_major__ == 14无法区分 Apple Clang 14.0.0 和 14.0.3
跨编译器条件编译的实用写法
别写嵌套四层 #ifdef,用“先分大类、再细分”策略,兼顾可读性与健壮性:
#if defined(_MSC_VER)
// MSVC 分支
#if _MSC_VER >= 1930
// VS 2022 17.0+
#endif
#elif defined(__clang__)
// Clang 分支(含 Apple Clang)
#if defined(__apple_build_version__)
// Apple Clang,用 __apple_build_version__ 做精确判断
#elif __clang_major__ >= 16
// 标准 Clang 16+
#endif
#elif defined(__GNUC__)
// GCC 分支
#if __GNUC__ >= 12
// GCC 12+
#endif
#endif
关键点:
- Apple Clang 必须优先检查
__apple_build_version__,否则会被__clang__分支误捕获 - 不要用
__GNUG__替代__GNUC__,前者在某些 MinGW 配置下未定义 - MSVC 的
_MSVC_LANG是 C++ 标准版本(如202002L),和编译器版本无关,别混用
容易被忽略的陷阱
最常踩坑的地方不在宏本身,而在构建系统和交叉编译场景:
- Clang 使用
-gcc-toolchain模拟 GCC 头文件路径时,__GNUC__仍会定义,但实际调用的是 Clang 前端——此时应以__clang__为准,忽略__GNUC__ - CMake 中
COMPILER_ID可能返回 "Clang",但若用户手动设置-D__GNUC__=12,预处理器仍会认这个宏,导致逻辑错乱 - 某些国产编译器(如 OpenArk、毕昇)兼容 GCC 宏,但
__VERSION__字符串含中文或特殊字段,正则解析必然失败 - 内核模块编译(如 Linux kernel build)禁用大部分标准宏,
__KERNEL__存在时,__GNUC__可能为真但__STRICT_ANSI__也被定义,需额外检查
真正可靠的判断永远基于宏是否存在及其数值,而不是字符串匹配或外部命令查询。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











