跨平台开发要求同一套源码在windows、linux、macos上编译通过且行为一致;需用std::filesystem::path处理路径、统一utf-8编码并在系统边界转换、封装平台差异至底层实现、以cmake声明式管理构建契约。

跨平台开发不是“让代码在多个系统上跑起来”,而是让同一套源码在 Windows、Linux、macOS 上编译通过、行为一致、无需手动改路径或重写线程逻辑。做不到这点,就只是“多平台适配”,不是真正跨平台。
用 std::filesystem::path 替代字符串拼接路径
硬编码 "C:\data\config.txt" 或 "/usr/local/etc/app.conf" 是跨平台第一大雷。Windows 用 '\',Linux/macOS 用 '/',但更麻烦的是:Unicode 路径在 Windows 必须走宽字符 API,而 Linux 默认 UTF-8 —— 直接传 std::string 给 CreateFileW 会静默失败。
std::filesystem::path 自动处理分隔符转换、编码桥接(配合 std::filesystem::u8path)、甚至支持 operator/ 拼接:
std::filesystem::path p = std::filesystem::u8path(u8"/home/user"); p /= "data"; p /= "config.json"; // 自动转为 在 Windows 下
注意:std::filesystem 需要 C++17 且链接 -lstdc++fs(GCC)或启用 MSVC 的 /std:c++17 和 /D _SILENCE_CXX17_FILESYSTEM_DEPRECATION_WARNING。若项目卡在 C++14,别自己写跨平台路径类——直接上 boost::filesystem::path,它比手撸健壮得多。
别信 #ifdef _WIN32 能解决所有问题
条件编译容易演变成“补丁堆叠”:一个函数里嵌套三层 #ifdef,_WIN32 下用 WaitForSingleObject,Linux 用 pthread_cond_wait,macOS 又得切到 dispatch_semaphore。这种代码不可测、难调试、一加新平台就得重写整块。
真正可维护的做法是定义统一接口,把平台差异锁死在 cpp 文件里:
- 头文件只暴露
class ThreadSignal { public: void wait(); void notify_one(); }; - Windows 实现用
HANDLE+WaitForSingleObject - POSIX 实现用
pthread_mutex_t+pthread_cond_t - CMake 中用
target_sources(... PRIVATE signal_win.cpp signal_posix.cpp)控制编译哪份
这样上层逻辑完全无感,新增 Android 平台?只加一个 signal_android.cpp,不碰任何业务代码。
CMake 不是生成器,是跨平台契约
很多人以为 CMake 就是“为 VS 生成 sln,为 Linux 生成 Makefile”。错。它的核心价值是把“编译什么、怎么编译、依赖谁”从 IDE 或 shell 脚本里抽出来,变成一份声明式契约。
关键配置必须显式声明:
- 用
set(CMAKE_CXX_STANDARD 17)固定语言标准,别依赖编译器默认值 - 用
find_package(Threads REQUIRED)而不是手动target_link_libraries(app pthread)—— macOS 需要pthread,Windows 根本不需要 - 第三方库必须通过
find_package或add_subdirectory引入,禁止硬编码/usr/lib/x86_64-linux-gnu/libboost_filesystem.so
如果 CMakeLists.txt 里出现 if(WIN32) 判断来设置不同 include_directories,说明抽象没做好——应该用 find_package(Boost REQUIRED COMPONENTS filesystem system) 让 FindBoost 模块自己处理路径。
字符编码必须统一为 UTF-8,且仅在边界转换
Windows 控制台默认是 GBK,VS 编辑器默认保存为 UTF-8 with BOM,Linux 终端认 UTF-8 without BOM —— 这些都不是你的代码该操心的。规则只有一条:程序内部所有字符串(std::string)一律 UTF-8 编码;只在与系统 API 交互的最外层做转换。
例如打开文件:
- 输入路径来自用户或配置文件 → 假设是 UTF-8
std::string - Windows 下调
CreateFileW前,用MultiByteToWideChar(CP_UTF8, ...)转成std::wstring - Linux 下直接传给
open(),它本就期望char*UTF-8
千万别在中间层(比如日志函数、配置解析器)反复转码。也别用 std::locale 或 setlocale——它们在多线程下不可靠,且各平台实现差异极大。
最易被忽略的一点:二进制数据和文本必须严格区分。读取图片、音频、网络包时,永远用 std::ios::binary 打开文件,否则 Windows 下的
会被自动替换,导致校验失败或解析崩溃。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











