





























要深刻理解 MSVC 的 /Zc 编译命令,我们必须先聊聊微软一段长达数十年的“黑历史”。
在 20 世纪 90 年代到 21 世纪初,微软的 Windows 帝国如日中天。当时微软的 Visual C++ 编译器(MSVC)为了追求编译速度、契合 Windows 底层的特定 API,加之当时国际标准(C++98)本身也不够完善,微软在编译器中引入了大量独创的、不符合国际标准的“魔改语法”和特权。
比如:允许非左值引用绑定到临时变量、不严格区分嵌套模板的空格、老旧的宏预处理器等。
然而,随着 C++11 开启了现代 C++ 的大航海时代,国际标准变得极为严苛,GCC 和 Clang 编译器因严格遵守标准而迅速崛起。此时,微软面临一个巨大的两难境地:
为了解决这个历史包袱,微软精心设计了一个**渐进式的“拨乱反正”开关——/Zc**。
/Zc?正如前面提到的,/Zc 是一个组合前缀:
Z:MSVC 中关于语言特性、代码生成的系列开关前缀。c:代表 Conformance(符合性),即“向 C++ 国际标准看齐”。它的语法规则是:/Zc:特性名称[+|-](不加符号默认等同于 +)。
/Zc:特性:开启严格标准模式。哪怕会让你的老代码报错,也要强制按国际标准编译。/Zc:特性-:关闭严格标准,退回到微软历史上的“纵容/魔改”模式,以保证老代码能跑通。/Zc 选项大盘点随着 Visual Studio 2022 到如今最新的 Visual Studio 2026 的演进,许多 /Zc 开关已经默认开启,但了解它们依然是进阶 C++ 工程师的必修课。以下是开发中最常用、最核心的选项:
/Zc:__cplusplus(强烈推荐手动开启)__cplusplus 宏永远固执地输出 199711L(C++98 的版本号)。这是为了防止极其古老的 Windows SDK 报错。__cplusplus 宏正确输出当前标准的版本号(如 C++17 输出 201703L)。/Zc:preprocessor(现代 C++ 必备)/Zc:char8_t-(带减号,向下兼容利器)char8_t 类型用于 UTF-8 字符串。这导致旧代码中所有的 u8"hello" 无法再隐式转换或赋值给普通的 std::string 或 char*。char 类型处理。/Zc:wchar_t(已默认开启,历史意义重大)wchar_t 直接定义为了 unsigned short(无符号短整型)的别名(通过 typedef)。wchar_t 恢复为 C++ 国际标准中规定的独立原生内置类型。-,void foo(wchar_t) 和 void foo(unsigned short) 就会被视为重复定义,导致严重的函数重载冲突。/Zc:inline(优化编译期和程序体积)inline 函数,但其实全篇代码都没去调用它,MSVC 依然会死板地把它编译进 .obj 文件里,最后加大 .exe 的体积。inline 函数或模板函数未被使用,或者它没有定义,编译器会直接将其剔除。/Zc?如果你在使用 CMake 进行现代 C++ 开发,微软其实已经意识到了天天让开发者手动配这些选项非常痛苦。
从近几年的现代 MSVC 开始,微软引入了一个“终极外挂”参数:/permissive-(意为“关闭宽容模式”)。
当你开启了 /permissive- 时,它会自动在幕后把绝大多数 /Zc 选项(如 /Zc:referenceBinding、/Zc:strictStrings 等)一键全部调成严格符合标准的状态。
因此,在现代 CMake 中,针对微软编译器的标准标准配置通常长这样:
if(MSVC)
# 1. 一键开启全面严格标准模式(相当于开启了一大堆 /Zc)
add_compile_options(/permissive-)
# 2. 依然需要手动补上的漏网之鱼(由于历史原因,/permissive- 没包含它们)
add_compile_options(/Zc:__cplusplus)
add_compile_options(/Zc:preprocessor)
endif()
通过这一套组合拳,你就把原本满是历史包袱的 MSVC,彻底伪装成了一个像 GCC 和 Clang 一样纯正、现代的、无 Bug 的标准 C++ 编译器!
permissive 的音标与本义该词源自拉丁语动词 permittere(允许、放任),在日常英语中它是一个形容词:
在微软 MSVC 编译器的语境下,/permissive 被借用为一个技术术语,用来形容编译器的“宽容度”。
/permissive(默认或老版本状态):宽容模式/permissive-(末尾带减号):关闭宽容模式(即:严格标准模式)/permissive- 带有减号,表示“封杀/关闭这种纵容的态度”。微软引入 /permissive- 这个名字非常带有自嘲的幽默感。加了这个参数,就是命令编译器:“收起你过去几十年对 Windows 老旧代码的‘溺爱与纵容’,给我按照国际标准严格执法!”。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。