准确区分msvc、clang、gcc应优先检测_msc_ver(存在即msvc或clang-cl兼容模式),再判__clang__且未定义_msc_ver为原生clang,最后判__gnuc__且未定义__clang__为真正gcc;__cplusplus仅表标准版本,不可用于识别厂商。

直接看 _MSC_VER、__clang__、__GNUC__ 这三个宏是否存在且有效,就能准确区分 MSVC、Clang、GCC —— 其他方式(比如查 __cplusplus 或 sizeof 行为)不可靠,也非标准做法。
怎么判断是不是 MSVC 编译器
只认 _MSC_VER:它在 MSVC 和 clang-cl 下都会被定义,且值稳定递增(VS2019=1920,VS2022=1930)。这是唯一可信赖的 MSVC 标识。
-
#if defined(_MSC_VER)✅ 安全写法 -
#ifdef _MSC_VER && _MSC_VER >= 1930❌ 预处理器不支持&&,语法错误 - 别用
_MSC_FULL_VER:构建号变化无规律,无法用于条件编译 - Clang 启用
-fms-compatibility时也会定义_MSC_VER,此时它就是“MSVC 兼容模式”,该按 MSVC 路径走
怎么区分 Clang 和 GCC
Clang 默认会定义 __GNUC__(为了兼容),所以单靠它不能断定是 GCC。必须组合排除:
-
#if defined(__clang__) && !defined(_MSC_VER)→ 原生 Clang(非clang-cl) -
#if defined(__GNUC__) && !defined(__clang__)→ 真正的 GCC(或 ICC/TCC 等 GNU 兼容编译器) - 如果只写
#ifdef __GNUC__,在 Clang 下也会进分支,可能触发 GCC 特有语法报错(比如__attribute__((optimize("O3"))))
为什么不能用 __cplusplus 判断编译器厂商
__cplusplus 只表示 C++ 标准版本(如 201703L),不是编译器身份标识。g++ 和 clang++ 都会定义它,GCC 的 C 编译器 gcc 不定义它 —— 但这和“是否是 GCC 编译器”无关,因为 g++ 才是 C++ 前端。
- 想判断“当前是不是 C++ 编译器”?看
__cplusplus是否定义 ✅ - 想判断“是不是 GCC 厂商的编译器”?必须靠
__GNUC__+ 排除__clang__✅ - 用
sizeof('a') == 1或空结构体大小来区分 gcc/g++?属于未定义行为依赖,不同版本可能变,绝对不要用
clang-cl 下 _MSC_VER 和 __clang__ 同时存在怎么办
这不是冲突,而是设计使然 —— 它意味着你正在使用 Clang,但目标 ABI、头文件、链接规则都对齐 MSVC。此时应优先响应 _MSC_VER,而非强行走 Clang 分支。
- 例如:需调用 Windows SDK 头文件、使用
__declspec(dllexport)、适配 CRT 行为时,以_MSC_VER为准 - 若需启用 Clang 特有警告(如
-Wimplicit-fallthrough)或优化(如__builtin_assume),再用__clang__控制 - 混用时注意顺序:先
#if defined(_MSC_VER),再#elif defined(__clang__),避免clang-cl被误判为原生 Clang
最易忽略的一点:clang-cl 下 _MSC_VER 和 __clang__ 同时存在,此时宏的语义不是“既是 MSVC 又是 Clang”,而是“Clang 模拟 MSVC”。条件编译逻辑必须反映这个事实,而不是当成二选一的互斥状态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











