最可靠直接看 _WIN32 和 __linux__ 就够了:_WIN32 在所有 Windows 工具链(MSVC、MinGW、Clang)下均定义,包括64位系统;__linux__ 是 GCC/Clang 在 Linux 目标下的事实标准宏,二者互斥且不依赖宿主系统。

用 _WIN32 和 __linux__ 判断 Windows/Linux 最可靠
直接看这两个宏就够了:_WIN32 在所有 Windows 工具链(MSVC、MinGW、Clang for Windows)下都定义,包括 64 位系统;__linux__ 是 GCC/Clang 在 Linux 目标下定义的事实标准(注意双下划线,linux 或 LINUX 不生效)。它们互斥——交叉编译时不会同时出现,也不依赖你当前在哪个系统上敲命令。
-
_WIN32比WIN32可靠得多,后者是 CMake 的内部变量,编译器根本不定义 -
__linux__比__unix__精准,因为 macOS、FreeBSD、WSL 都定义__unix__,容易误判 - Android 会同时定义
__linux__和__ANDROID__,若需区分桌面 Linux,得额外排除__ANDROID__
macOS 和其他 Unix-like 系统怎么加判断分支
macOS 必须用 __APPLE__,不能只靠 __unix__ 或 __MACH__ 单独判断——iOS 也定义 __APPLE__,但多数跨平台逻辑对两者兼容;若需严格区分 macOS(非 iOS),可加 defined(__APPLE__) && !defined(__ANDROID__),一般够用。
- BSD 系统有各自宏:
__FreeBSD__、__OpenBSD__、__NetBSD__,不共享__linux__ - HarmonyOS 用
__harmony__,它和__linux__不共存,需独立分支 - 别写嵌套三层的
#if defined(A) && defined(B) && !defined(C),优先级顺序比复杂条件更易维护
为什么不能用运行时方式比如 getenv("OS") 或 system("uname")
这些方法在构建阶段就失效:容器里没 shell、嵌入式环境没 uname、沙箱禁 system 调用,而且返回值不可控——getenv("OS") 在 Linux/macOS 下直接返回 nullptr,system("uname -s") 还可能被注入恶意参数。
- 跨平台库(Qt、Boost、std::filesystem)底层全靠编译期宏分发,不是字符串匹配
- 真正需要运行时识别的场景极少(如插件加载不同后缀的动态库),此时应靠接口约定(如函数指针表),而非解析系统名
- 用
g++ -dM -E /dev/null | grep -i linux可实时验证当前编译器到底定义了哪些宏
CMake 中怎么同步控制宏定义和构建行为
CMake 的 CMAKE_SYSTEM_NAME 是构建期权威标识,和代码里的预定义宏要对齐。例如 Linux 下 CMAKE_SYSTEM_NAME 是 Linux,你就该在 C++ 里用 __linux__ 分支;若用 MinGW 编译 Windows 目标,CMAKE_SYSTEM_NAME 是 Windows,C++ 侧必须用 _WIN32,而不是靠 __MINGW32__ ——后者只是工具链提示,不是操作系统信号。
立即学习“C++免费学习笔记(深入)”;
- 推荐在 CMakeLists.txt 里用
target_compile_definitions(mylib PRIVATE $<linux>)</linux>而非硬写-D__linux__,避免漏掉构建配置 - 第三方头文件(如 Qt)可能自带平台宏(
Q_OS_WIN),务必把它包含在你自定义#ifdef之后,否则会被覆盖 - 路径拼接、线程模型、socket API 这些差异点,不能只靠宏切换函数名,得封装成统一接口,宏只用来选实现


















