c++oding="utf-8" ?>
c++ 没有跨编译器的宏可直接获取完整版本字符串,所有可用宏均为整数型、分段编码且互不兼容;msvc 用 _msc_ver(如1940)编码主次版本,_msc_full_ver(如194033812)含补丁号但末三位为内部构建号。

直接说结论:C++ 没有统一、跨编译器的宏来获取“完整版本号字符串”(比如 "14.36.32532"),所有可用宏都是整数型、分段编码的,且各编译器定义方式互不兼容——想靠宏拼出 clang++ 16.0.6 或 MSVC 19.40.33812 这样的完整标识,必须手动查表+条件分支,不能偷懒。
怎么用宏识别 MSVC 编译器及主版本?
_MSC_VER 是唯一稳定可靠的 MSVC 版本宏,但它不是“版本号”,而是微软自定义的整型编码:高两位是主版本,低两位是子版本。例如 _MSC_VER == 1940 表示 MSVC 19.40(即 VS 2022 17.10),_MSC_FULL_VER 则包含补丁号(如 194033812),但需注意它末三位是内部 build 号,不等于公开发布的补丁序号。
-
_MSC_VER必须存在,且只在 MSVC 下定义;其他编译器(Clang/LLVM on Windows、GCC)不会定义它 - 不要用
_MSC_VER >= 1930来判断“是否支持 C++20 概念”,因为功能支持和版本号不严格对齐,应改用__cpp_concepts >= 201907L -
_MSC_FULL_VER的第三位数字(百位)可能为 0,例如193032999表示 19.30.32999,不能简单拆成19.30.32—— 百位缺失时要补零
怎么区分 Clang 和 GCC 并读取其版本字段?
Clang 声称兼容 GCC,所以会定义 __GNUC__ 等宏,但优先检测 __clang__ 更可靠;而 GCC 从不定义 __clang__。二者都提供三段式整数宏:__clang_major__/__GNUC__、__clang_minor__/__GNUC_MINOR__、__clang_patchlevel__/__GNUC_PATCHLEVEL__。
- Clang 在启用
-fms-compatibility时可能定义_MSC_VER,此时必须先判断__clang__再判断_MSC_VER,否则误判为 MSVC - GCC 12+ 开始支持
__VERSION__字符串(如"14.2.0"),但它是编译时常量字符串,无法用于预处理条件判断,仅适合std::cout - Clang 的
__clang_patchlevel__不一定对应官网发布的 patch 序号(如 Clang 16.0.6 中__clang_patchlevel__ == 6成立,但某些 snapshot 构建中它可能是 0)
为什么不能依赖 __VERSION__ 或 __cplusplus 获取编译器身份?
__VERSION__ 是编译器自定义字符串,GCC 输出带空格的长描述(如 "14.2.0 (Ubuntu 14.2.0-1ubuntu1)"),Clang 输出类似 "Ubuntu clang version 16.0.6",MSVC 根本不定义它;而 __cplusplus 只反映标准支持级别(如 202002L),与编译器厂商、版本完全无关。
- 试图用
#if defined(__VERSION__) && __VERSION__[0] == 'U'解析字符串是未定义行为——预处理器不支持数组索引 - 有些交叉编译工具链(如 ARM GCC)会篡改
__VERSION__,使其与真实版本不符,仅作日志参考尚可,不可用于逻辑分支 -
__cplusplus在 MSVC 中长期滞后(即使开启 /std:c++20,旧版 MSVC 仍报告201703L),必须配合_MSC_VER使用
实际项目中推荐的检测组合写法
一个健壮的检测块需同时满足:能区分编译器身份、能提取主次版本用于特性开关、不因构建环境差异失效。以下是最小可行模式:
#if defined(_MSC_VER) && !defined(__clang__) // 真正的 MSVC #define COMPILER_MSVC 1 #define COMPILER_VERSION_MAJOR (_MSC_VER / 100) #define COMPILER_VERSION_MINOR (_MSC_VER % 100) #define COMPILER_VERSION_PATCH (_MSC_FULL_VER % 1000) #elif defined(__clang__) // Clang(含 clang-cl) #define COMPILER_CLANG 1 #define COMPILER_VERSION_MAJOR __clang_major__ #define COMPILER_VERSION_MINOR __clang_minor__ #define COMPILER_VERSION_PATCH __clang_patchlevel__ #elif defined(__GNUC__) // GCC(不含 clang) #define COMPILER_GCC 1 #define COMPILER_VERSION_MAJOR __GNUC__ #define COMPILER_VERSION_MINOR __GNUC_MINOR__ #define COMPILER_VERSION_PATCH __GNUC_PATCHLEVEL__ #endif
注意:这个组合没处理 Intel ICC、PGI、EDG 等小众编译器;如果项目需要支持它们,得单独加 __INTEL_COMPILER、__PGI 等分支——但绝大多数现代 C++ 项目只需覆盖前三者。真正的麻烦在于,同一编译器不同平台下的宏行为可能微调(比如 macOS 上 Clang 对 __apple_build_version__ 的处理),这些细节往往只有在 CI 失败后才暴露出来。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











