跨平台类型判断需区分编译时与运行时决策:编译时用标准宏或CMake变量并强制未覆盖平台报错,运行时用缓存枚举值,语言级隔离按文件分离实现,优先采用标准库抽象处理路径、字节序和线程存储。

跨平台类型判断逻辑的核心在于区分“编译时决策”和“运行时决策”,并根据实际需求选择合适的技术路径。不能一概而论用宏或用枚举,关键看判断发生时机、精度要求和性能约束。
编译时判断:用预处理器宏或构建系统变量
适用于代码结构差异大、需彻底排除某平台逻辑、或调用平台专属 API 的场景。此时判断必须在编译前完成,避免无效代码进入构建流程。
- C++ 中优先使用编译器注入的标准宏:
#ifdef __linux__(不是linux)、#ifdef _WIN32(覆盖 32/64 位 Windows)、#ifdef __APPLE__(macOS/iOS),并注意__ANDROID__与__linux__可共存,不能互相替代 - CMake 中推荐用
CMAKE_SYSTEM_NAME字符串变量(如"Linux"、"Darwin"、"Windows"),比UNIX或APPLE更精确,尤其利于区分 macOS 与 Linux - 务必补上
#else #error "Unsupported platform",强制暴露未覆盖平台,防止静默走错分支
运行时判断:用统一接口封装 + 枚举或字符串识别
适用于需要动态响应环境变化、插件热加载、或同一二进制适配多目标设备的场景。此时判断发生在程序启动或运行中,但需避免重复计算。
- Unity 中用
Application.platform返回RuntimePlatform枚举值(如Android、IPhonePlayer、WebGLPlayer),比宏更灵活,且支持 Unity 新增平台(如 VisionOS) - 建议缓存结果,例如用静态只读属性封装
IsMobile,避免每次调用都查Application.isMobilePlatform - 不要混用宏和运行时判断——比如在
#if UNITY_IOS块内再写if (Application.platform == ...),属于冗余且易出错
语言级隔离:按文件粒度分离平台实现
适合 Go、Rust 等支持构建标签或条件编译的语言,让不同平台代码物理隔离,彻底规避符号冲突和链接错误。
- Go 使用文件命名约定:
startup_linux.go、startup_windows.go、startup_darwin.go,编译器自动按目标GOOS选取 - 也可配合
//go:build标签(如//go:build linux),比运行时runtime.GOOS更安全,避免因函数未定义导致编译失败 - C++ 虽无原生文件级平台标记,但可通过 CMake 控制源文件列表:
if(WIN32) target_sources(app PRIVATE src/win32_impl.cpp) endif()
路径与基础类型:优先使用标准库抽象
很多“平台差异”其实已有成熟解法,不必自己硬判。过度依赖手动判断反而增加维护成本和出错概率。
- C++17 起,用
std::filesystem::path拼接路径,自动处理/与\差异,无需#ifdef切分隔符 - 大小端判断不用依赖编译器私有宏(如
__BYTE_ORDER__),改用std::endian(C++20)或运行时探测(*(char*)&uint32_t{1} == 1) - 线程局部存储优先用
thread_local(MSVC 2015+ / GCC 4.8+ / Clang 3.3+ 均支持),而非__declspec(thread)或__thread等扩展写法

















