必须依赖预定义宏组合解析:GCC用__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__三宏字符串化拼接;Clang优先判__clang__再取__clang_major__等三宏;MSVC须查表映射_MSC_VER(如1938→VS2022 17.8),不可直接换算。

要准确识别C++编译时所用的编译器及其完整版本号,必须依赖预定义宏——不同编译器(GCC、Clang、MSVC、ICC等)在预处理阶段注入的宏各不相同,且版本编码规则互异;仅靠__GNUC__或_MSC_VER无法直接得出如“GCC 13.2.0”或“MSVC 19.38.33135”这样的可读版本字符串,需组合多个宏并做数值解析。
识别GCC及其完整版本号
GCC使用三重宏表示版本:__GNUC__为主版本,__GNUC_MINOR__为次版本,__GNUC_PATCHLEVEL__为修订号。三者拼接即为标准语义化版本。
第一步:检查__GNUC__是否已定义,未定义则非GCC系编译器。
第二步:用预处理器字符串化将三个宏转为字面量,例如:#define STR(x) #x → STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__),展开后得"13.2.0"类字符串。
立即学习“C++免费学习笔记(深入)”;
注意:GCC 12起新增__VERSION__宏,其值为编译器自带字符串(如"13.2.0"),但该宏不可用于条件编译判断,仅作运行时日志输出用。
识别Clang及其完整版本号
Clang兼容GCC宏,但自身提供更精确的__clang_major__、__clang_minor__、__clang_patchlevel__三元组,且__clang_version__为常量字符串(如"16.0.6")。
方法一:优先检测__clang__宏是否存在,存在则排除GCC误判。
方法二:组合__clang_major__、__clang_minor__、__clang_patchlevel__生成版本号,这是最可靠方式——【Clang 15+起,__clang_patchlevel__才稳定可用,旧版可能为0或未定义】。
方法三:直接使用__clang_version__,但该宏是字符串字面量,不能用于#if条件分支,仅适合static_assert或日志。
识别MSVC及其完整版本号
MSVC不提供主/次/修订三级宏,仅用_MSC_VER一个整数编码版本,需查表映射。例如_MSC_VER == 1938对应Visual Studio 2022 17.8(即MSVC 14.38)。
第一步:确认_MSC_VER已定义且大于等于1900(VS2015起)。
第二步:用#if链式匹配常见值:#if _MSC_VER >= 1938 && _MSC_VER → "MSVC 14.38 (VS2022 17.8)"。
第三步:对未知_MSC_VER值,可计算主版本:(_MSC_VER / 100)得工具集号(如1938→19),再查微软官方文档确认对应VS年份与更新号。
注意:_MSC_FULL_VER包含补丁信息(如193833135),但末三位不保证有意义,不可直接拆分为补丁号。
识别Intel C++ Compiler(ICX/ICPC)
ICX(基于LLVM)和传统ICPC行为不同,需分开判断。
方法一:若定义了__INTEL_LLVM_COMPILER,则为ICX,其值为类似GCC的五位数(如20240000 → 2024.0.0),高位两位是年份,中间两位是月份,末位为补丁序号。
方法二:若定义了__INTEL_COMPILER且未定义__INTEL_LLVM_COMPILER,则为传统ICPC,__INTEL_COMPILER值为六位数(如202100 → 2021.0),前四位为年份,后两位为更新号。
【ICX 2023.2起弃用__INTEL_COMPILER,仅保留__INTEL_LLVM_COMPILER;混用会导致版本误判】。
跨编译器统一版本字符串生成(C++11及以上)
用constexpr函数在编译期生成版本字符串字面量,避免预处理器拼接的局限性。
先定义宏检测分支:#ifdef __GNUC__ → 调用gcc_version_string();#elif defined(__clang__) → 调用clang_version_string();#elif defined(_MSC_VER) → 调用msvc_version_string()。
每个函数内部用constexpr if(C++17)或模板特化(C++11)展开数值,逐位转字符,最终返回std::string_view或字符数组。
这一步操作起来很简单,直接把函数声明加到头文件里,所有源文件包含即可获得统一格式的CURRENT_COMPILER_VERSION。


















