跳转到主内容
极星编程网:以代码为星,赴技术山海!

C++如何根据宏定义判断当前系统当前的编译器完整版本 _ 汇总表【干货】

无法直接获取完整版本字符串,需用编译器特有宏(如GCC的__GNUC__等、Clang的__clang__等、MSVC的_MSC_VER)手动拼接,且须注意跨编译器兼容性与宏定义差异。 没有标准宏能直接给出“完整版本字符串”,所有可用宏都只提供数字型主/次/补丁号,必须手动拼接;依赖编译器自身定义的宏,跨编译器不可互换。 如何获取 GCC 的主次补丁号(
__GNUC__
、
__GNUC_MINOR__
、
__GNUC_PATCHLEVEL__
) GCC 用三个独立宏分别表示主版本、次版本和补丁号,例如 GCC 12.3.0 对应
__GNUC__ == 12
、
__GNUC_MINOR__ == 3
、
__GNUC_PATCHLEVEL__ == 0
。注意:
__GNUC_PATCHLEVEL__
在旧版 GCC(如 4.8 之前)可能未定义,需先检查是否已声明。 实操建议: 始终用
#if defined(__GNUC__) && __GNUC__ >= 5
这类守卫判断,而非直接展开 拼接完整版本时,用预处理器字符串化(
#
)配合
__GNUC__
等宏需借助中间宏,否则会直接展开为数字字面量而非字符串 不要尝试用
__VERSION__
宏做逻辑判断——它是字符串字面量(如
"12.3.0"
),无法参与
#if
数值比较 Clang 如何区分它和 GCC(
__clang__
、
__clang_major__
、
__clang_minor__
、
__clang_patchlevel__
) Clang 定义了
__clang__
为 1,并提供三组数字宏。关键点在于:Clang 会**同时定义**
__GNUC__
系列宏(默认兼容 GCC 4.2.1 接口),所以仅靠
__GNUC__
无法识别 Clang。必须优先检测
__clang__
。 立即学习 “ C++免费学习笔记(深入) ”; 常见错误现象: C知道 CSDN推出的一款AI技术问答工具 下载 代码里写
#ifdef __GNUC__
就进 Clang 分支,导致误判 把
__clang_patchlevel__
当作 Clang 自身补丁号——其实它对应的是 LLVM 的 patch 版本,和 Clang 发布版号不完全一致(例如 Clang 16.0.0 可能对应
__clang_patchlevel__ == 6
) 忽略
__apple_build_version__
:macOS 上的 Clang(Xcode 自带)还额外定义该宏,值为 Apple 内部构建号(如
14030022
),和开源 Clang 无关 MSVC 的版本宏(
_MSC_VER
)为什么不能直接拆成主次版本?
_MSC_VER
是一个四位或五位整数,比如 MSVC 19.38 对应
_MSC_VER == 1938
,MSVC 14.35 是
1435
。但它**不是纯数值编码**:19.38 → 1938,但 19.40 → 1940,而 19.41 → 1941 —— 表面上可除 100 取整,但微软从未承诺这种映射稳定。更麻烦的是,MSVC 2022 17.x 开始引入
_MSC_FULL_VER
(如
193833135
),其高 4 位是
_MSC_VER
,后续数字是内部 build 号,无公开语义。 实操建议: 用
#if _MSC_VER >= 1930
判断最低支持,别试图
#define MSC_MAJOR (_MSC_VER / 100)
需要“显示版本”时,硬编码映射表比实时计算更可靠(例如
1938 → "19.38"
)
_MSVC_LANG
是 C++ 标准语言模式(如
202002L
),和编译器版本无关,别混淆 跨编译器统一提取版本字符串的最小可行方案 没有银弹。最简健壮做法是:先确定编译器种类,再用各自数字宏拼接字符串,最后用预处理器字符串化。难点在 Clang 和 GCC 共存时的优先级,以及 MSVC 的非线性编码。 示例片段(可用于头文件):
#if defined(__clang__) # define COMPILER_NAME "Clang" # define COMPILER_VERSION_STR \ # __clang_major__ "." # __clang_minor__ "." # __clang_patchlevel__ #elif defined(__GNUC__) # define COMPILER_NAME "GCC" # define COMPILER_VERSION_STR \ # __GNUC__ "." # __GNUC_MINOR__ "." # __GNUC_PATCHLEVEL__ #elif defined(_MSC_VER) # define COMPILER_NAME "MSVC" # if _MSC_VER == 1938 # define COMPILER_VERSION_STR "19.38" # elif _MSC_VER == 1937 # define COMPILER_VERSION_STR "19.37" # else # define COMPILER_VERSION_STR "unknown" # endif #else # define COMPILER_NAME "unknown" # define COMPILER_VERSION_STR "unknown" #endif
真正复杂的地方在于:你要用这个版本号做什么。如果只是日志打印,字符串化够用;如果要条件编译某段仅 GCC 13+ 支持的属性(如
[[assume]]
),就必须回到数值宏做
#if
判断,且必须查清该特性实际落地的最早版本——文档写的“GCC 13”可能实际从 13.2 才可用。

相关文章