最可靠的方式是使用编译器预定义宏__linux__、_WIN32、__APPLE__加__MACH__判断平台,而非自定义宏或依赖__GNUC__等编译器宏,因平台与编译器无关,且这些宏是事实标准、无需维护。

直接看结论:用 __linux__、_WIN32、__APPLE__ 这类预定义宏最可靠,别手写 PLATFORM_LINUX 这种自定义宏去判断。
怎么写跨平台条件编译的 ifdefs
编译器自己会定义好系统相关宏,比如 GCC/Clang 在 Linux 下自动定义 __linux__,MSVC 和 MinGW 在 Windows 下都定义 _WIN32(注意不是 WIN32),macOS 下则有 __APPLE__ 加 __MACH__。这些是事实标准,不用猜也不用维护。
- Windows 判断只用
#ifdef _WIN32就够了,_WIN64是额外补充,不是必需 - Linux 不要写
#ifdef linux—— 这个宏不存在,正确的是__linux__(带双下划线) - macOS 必须同时检查
__APPLE__和__MACH__,单用__APPLE__可能在某些旧工具链里不稳 - 避免嵌套过深:
#if defined(_WIN32) || defined(__linux__)比连写三个#ifdef更易读
为什么不能依赖 __GNUC__ 或 __clang__ 判断平台
__GNUC__ 表示用了 GCC 兼容编译器,不代表运行在 Linux;Clang 在 Windows 上也能用(比如通过 clang-cl),此时 __clang__ 为真但系统仍是 Windows。平台 ≠ 编译器。
- 想开 POSIX 功能?看
__linux__或__APPLE__,不是看__GNUC__ - 要用 Windows API?只认
_WIN32,哪怕你用的是 Clang for Windows - 交叉编译时尤其危险:arm-linux-gnueabihf-gcc 会定义
__linux__,但不会定义__GNUC__以外的编译器宏来暗示系统
常见错误现象和坑点
最典型的是本地能编译,CI 上失败,或者 macOS 开发者收不到 Windows 特有 bug 报告——往往因为宏判断写错了。
立即学习“C++免费学习笔记(深入)”;
-
#ifdef WIN32:永远不触发,正确是_WIN32(前面多一个下划线) -
#if __linux__ == 1:没必要,__linux__是定义即真,值不重要 - 混用大小写:
#ifdef __APPLE__对,#ifdef __apple__错 - 忘了头文件依赖:比如在 Windows 分支里用了
winsock2.h,但没加#undef UNICODE前置控制,导致后续头文件行为异常
实际项目中怎么组织平台相关代码
别把所有平台逻辑塞进一个 .cpp 里硬扛。按功能拆,用头文件做薄层抽象更可持续。
- 声明统一接口,比如
get_current_time_ms(),在platform_linux.cpp、platform_win.cpp里分别实现 - 构建系统(CMake/Makefile)负责把对应文件加入编译,而不是靠宏在同一个文件里切逻辑
- 如果必须用宏,优先用
#if defined(...)而非#ifdef,防止宏被意外#undef后静默失效 - 在 CMake 中加
message(STATUS "Target platform: ${CMAKE_SYSTEM_NAME}"),和代码里的宏定义对齐校验
平台判断本身不难,难的是每次新增一个 target(比如嵌入式 FreeRTOS 或 WASM)时,是否还能快速定位该补哪个宏、哪个头文件、哪段链接选项——所以别省那几行 #ifdef,把判断逻辑收口到明确的位置,比到处散落更省调试时间。











