判断平台应优先用 _win32,再用 __apple__ && __mach__ 确保 macos(排除 ios),最后用 __linux__ 判 linux;需规避 __unix__ 模糊性,并在构建系统中统一注入宏。

怎么判断当前平台是 Windows、Linux 还是 macOS
靠 _WIN32、__linux__、__APPLE__ 这三个宏就够了,但必须注意它们的定义逻辑和重叠关系。Windows 下只有 _WIN32(MSVC 和 MinGW 都定义),Linux 下 __linux__ 一定为真(GCC/Clang 默认定义),macOS 同时定义 __APPLE__ 和 __MACH__,但仅靠 __APPLE__ 不够——因为 iOS/watchOS/tvOS 也定义它。
所以实际判断顺序应为:
- 先排除 Windows:
#ifdef _WIN32 - 再区分 Apple 生态:
#elif defined(__APPLE__) && defined(__MACH__)(确保是 macOS,不是 iOS) - 最后是 Linux:
#else或显式#elif defined(__linux__)
不建议用 __unix__ ——它在 macOS 和部分 BSD 上也定义,但语义模糊,无法精准对应 Linux。
为什么不能直接用 __linux__ 和 __APPLE__ 二选一
因为 macOS 的 Clang 会同时定义 __linux__ 吗?不会。但它会定义 __unix__、__APPLE__、__MACH__,而某些交叉编译环境(比如用 Linux 主机编译 macOS 目标)可能意外漏掉 __APPLE__,或误启了非标准宏。更现实的问题是:CMake 或 Meson 生成的构建系统可能覆盖或取消定义某些宏。
稳妥做法是把平台判定封装成一组互斥宏:
#ifndef PLATFORM_WINDOWS # ifdef _WIN32 # define PLATFORM_WINDOWS 1 # endif #endif <h1>ifndef PLATFORM_LINUX</h1><h1>if defined(<strong>linux</strong>) && !defined(<strong>ANDROID</strong>)</h1><h1>define PLATFORM_LINUX 1</h1><h1>endif</h1><h1>endif</h1><h1>ifndef PLATFORM_MACOS</h1><h1>if defined(<strong>APPLE</strong>) && defined(<strong>MACH</strong>) && !defined(<strong>ios</strong>)</h1><h1>define PLATFORM_MACOS 1</h1><h1>endif</h1><h1>endif</h1>
其中 !defined(__ios__) 是防 iOS 误判的关键;!defined(__ANDROID__) 避免 Android 被归入 Linux(虽然它基于 Linux 内核,但 ABI 和系统调用差异极大)。
通过 handsfree-windows CLI控制 Windows 本机应用 (UIA) 和浏览器 (Playwright) 的引导技能,用于自动化或测试桌面应用。
跨平台头文件路径与 API 差异怎么用宏控制
比如需要包含 socket 相关头文件:winsock2.h 在 Windows,sys/socket.h 在 Linux/macOS;又比如线程本地存储:__declspec(thread) 在 MSVC,__thread 在 GCC/Clang,但 macOS 的 Clang 对 __thread 支持有限,得退回到 pthread_key_t。
典型写法是分层抽象,而不是在业务代码里满屏 #ifdef:
// platform_thread_local.h #if PLATFORM_WINDOWS # define THREAD_LOCAL __declspec(thread) #elif PLATFORM_LINUX || PLATFORM_MACOS # if defined(__clang__) && PLATFORM_MACOS // macOS clang 不完全支持 __thread 用于非 POD 类型 # define THREAD_LOCAL __thread # else # define THREAD_LOCAL __thread # endif #else # error "Unsupported platform for THREAD_LOCAL" #endif
关键点:不要在每个 .cpp 里重复判断;把平台相关实现收进 platform_*.h,对外暴露统一接口名;宏定义尽量只做“有无”和“用哪个”,不做具体实现细节。
容易被忽略的 CMake 与编译器差异陷阱
CMake 默认不传递平台宏给源码,你得手动加:
-
target_compile_definitions(my_target PRIVATE PLATFORM_LINUX=$<bool:> PLATFORM_MACOS=$<bool:>)</bool:></bool:>不可靠——${APPLE}是 CMake 内部变量,不代表编译器看到的__APPLE__ - 正确做法是让 CMake 检测编译器并注入标准宏:
add_compile_definitions(_WIN32) # 仅 Windows,但更推荐用check_cxx_source_compiles实测宏是否生效 - MinGW 和 MSVC 对
_WIN32的处理一致,但 MinGW 可能额外定义__linux__(极少见),所以必须优先判断_WIN32,再判断其他
另一个坑:Clang on Windows(如 clang-cl)会定义 _WIN32,但也可能定义 __linux__ 如果用了错误的 sysroot;所以永远以 _WIN32 为最高优先级,且不依赖“非此即彼”的逻辑。
最复杂的不是写对宏,而是让所有构建路径(IDE 导入、CI 编译、用户手动 make)看到同一套宏定义;一旦某处漏了,sizeof(sockaddr_in6) 就可能错配,debug 成本远高于初期多写两行 guard。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










