最可靠的是用_win32和__linux__判断操作系统:_win32在所有windows工具链(msvc、mingw、clang)下均定义,包括64位系统;__linux__是gcc/clang在linux目标下的事实标准宏,二者互斥且纯编译期决策,不依赖宿主环境。

直接用 _WIN32 和 __linux__ 就够了,其他方式要么不可靠,要么根本不是编译期判断。
为什么只看 _WIN32 和 __linux__?
这两个宏由编译器在预处理阶段自动定义,不依赖运行环境、不调用 API、不查文件系统——纯编译期决策,最轻量也最可靠。
-
_WIN32在所有 Windows 工具链(MSVC、MinGW、Clang for Windows)下都定义,包括 64 位系统;WIN32不是编译器定义的,CMake 才用它,别混用 -
__linux__是 GCC/Clang 在 Linux 目标下定义的事实标准宏,注意是双下划线:__linux__✅,__linux❌,linux❌ - 它们互斥:交叉编译时不会同时出现,也不受你当前在哪台机器上敲命令影响
#ifdef _WIN32 后面该接 #else 还是 #elif defined(__linux__)?
取决于你是否需要为不同非 Windows 系统写差异化逻辑。如果只分“Windows vs 其他”,#ifdef _WIN32 + #else 足够;但若要给 Linux 单独加 epoll 或 /proc 访问,就得显式分支。
- 顺序必须是
_WIN32放最前——某些 MinGW 环境下__linux__不定义,但__unix__可能被误设,_WIN32是唯一强信号 - macOS、FreeBSD、Solaris 都不定义
_WIN32或__linux__,只用这两个宏会掉进#else分支,容易误判成 Linux - 主流项目建议写全:
#ifdef _WIN32→#elif defined(__linux__)→#elif defined(__APPLE__)→#else报错或兜底
Android 和 WSL 怎么办?
Android 是 Linux 内核,但 libc 是 bionic,不是 glibc;WSL 是 Linux 内核,但运行在 Windows 主机上——这两者都会定义 __linux__,但行为差异大,必须额外排除。
- Android 同时定义
__linux__和__ANDROID__,需用#if defined(__linux__) && !defined(__ANDROID__)区分桌面 Linux - WSL 下
_WIN32和__linux__不会共存,它走的是 Linux 工具链,所以只定义__linux__;但若你在 Windows 上用 MinGW 编译,就只定义_WIN32 - HarmonyOS 定义
__harmony__,和__linux__不共存,需独立分支
千万别用运行时方式判断
像 getenv("OS")、system("uname -s") 或 sizeof(void*) 这类方法,在构建阶段就失效或语义错误。
-
getenv("OS")在 Linux/macOS 下返回nullptr,Windows 下值也不统一;容器、嵌入式、沙箱环境可能根本没这些环境变量或 shell -
system("uname -s")可能被注入参数,返回字符串还要 strcmp,且无法在静态库或 freestanding 环境中使用 -
sizeof(void*) == 8只说明目标架构是 64 位,和操作系统类型无关——x86_64 Linux、macOS、Windows 都满足,但你没法据此选CreateFile还是open()
真正容易被忽略的点是:宏判断必须在头文件包含之前完成,否则 windows.h 和 unistd.h 的冲突会直接导致编译失败;而且路径分隔符、行尾符、信号处理等看似琐碎的细节,一旦漏判平台,就会在 CI 或客户环境里突然崩掉。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











