预定义宏可在编译时准确判断操作系统类型,无需运行时探测;\_win32、\_\_linux\_\_、\_\_apple\_\_是标准宏,需注意优先级与嵌套逻辑,避免非标准写法及跨平台兼容性问题。

用预定义宏判断操作系统类型
编译时就能确定目标平台,靠的是编译器内置的预定义宏。不同平台下这些宏自动生效,不需要运行时探测,也避免了依赖外部命令或文件系统路径。
常见组合如下:
-
_WIN32:Windows(32 或 64 位都定义,_WIN64可进一步区分) -
__linux__:Linux(注意双下划线,GCC/Clang 都支持) -
__APPLE__:macOS(必须配合__MACH__才能确认是 macOS 而非其他 Darwin 系统,但实际中几乎只用于 macOS)
别用 WIN32(没下划线)或 LINUX 这类非标准写法——它们不是编译器保证定义的宏,容易失效。
避免把 __APPLE__ 当成 macOS 的唯一依据
__APPLE__ 在所有基于 Darwin 的系统上都会定义,比如 iOS、tvOS 或旧版 Darwin 系统。但如果你只面向桌面开发,通常默认它就代表 macOS。真要严格区分,得加一层判断:
#ifdef __APPLE__ # include <targetconditionals.h> # if TARGET_OS_MAC && !TARGET_OS_IPHONE // 确实是 macOS # endif #endif</targetconditionals.h>
不过 TargetConditionals.h 是 Apple SDK 特有头文件,跨平台项目里引入它会破坏可移植性。多数情况下,只检查 __APPLE__ 就够用了,尤其当你明确只构建 macOS 桌面应用时。
运行时判断不可靠,也不必要
有人想调用 uname()(Linux/macOS)或 GetVersionEx()(Windows)来“运行时检测”,这既增加依赖又引入条件编译复杂度。而且 C++ 编译产物本身是平台绑定的:你不可能在 Windows 上跑出一个 Linux 的可执行文件,反过来也一样。
所以除非你在写跨平台动态库并需要根据加载环境调整行为(极少见),否则运行时判断纯属多余。预编译宏已经足够、更轻量、更安全。
宏嵌套和逻辑优先级容易写错
多个平台宏共存时,顺序和括号很重要。例如下面这段常见错误写法:
#if defined(_WIN32) || defined(__linux__) && !defined(__APPLE__)
由于 && 优先级高于 ||,这等价于:_WIN32 为真,或者(__linux__ 为真且 __APPLE__ 未定义)。结果是 macOS 下也可能误入 Linux 分支。
正确写法必须加括号:
#if defined(_WIN32) // Windows #elif defined(__linux__) // Linux #elif defined(__APPLE__) // macOS #endif
用 #elif 链比混用 &&/|| 更清晰,也更难出错。
真正麻烦的不是怎么写判断,而是后续分支里调用的 API 是否真的跨平台——比如 CreateFile() 和 open() 行为差异极大,光靠宏开关不能解决语义兼容问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











