Windows 下需用 CreateFileMapping + MapViewOfFile 替代 mmap,二者语义相近但参数、错误处理、资源清理差异大;Linux 用 open/mmap/munmap,Windows 需两级句柄管理且偏移必须页对齐。

Windows 和 Linux 下 mmap 等价物怎么选
直接说结论:mmap 在 Linux/macOS 可用,Windows 没有同名函数,得用 CreateFileMapping + MapViewOfFile。二者语义接近,但参数逻辑、错误处理、清理方式差异明显,混用会导致崩溃或静默失败。
常见错误是写完 Linux 版本后直接改个头文件就往 Windows 上跑,结果 mmap 返回 MAP_FAILED(其实是未定义),或者 MapViewOfFile 返回空指针却没检查——这俩都算“没映射成功”,但原因完全不同。
- Linux:打开文件用
open(),保护标志用PROT_READ,映射类型用MAP_PRIVATE(只读场景足够) - Windows:必须用
GENERIC_READ打开文件,CREATE_FILE_MAPPING的flProtect设为PAGE_READONLY,MapViewOfFile的dwDesiredAccess必须匹配(如FILE_MAP_READ) - 大小参数注意:Linux 传字节数,Windows 的
dwMaximumSizeHigh/dwMaximumSizeLow是 64 位 size 的拆分,别直接传(DWORD)size截断
如何封装成统一接口避免平台分支污染业务逻辑
不建议在每个读取点都写 #ifdef _WIN32 —— 一旦加写权限、偏移控制、自动大小探测,条件编译会迅速失控。推荐用小结构体封装句柄/指针+长度,并隐藏平台细节:
struct MappedView {
void* data = nullptr;
size_t size = 0;
bool valid() const { return data != nullptr && size > 0; }
~MappedView() { if (data) unmap(); }
private:
void unmap();
};unmap() 内部再按平台调用 munmap(data) 或 UnmapViewOfFile(data) + CloseHandle(hMap)(注意 Windows 还要关 hFile)。关键点是:Windows 的映射对象(HANDLE)和视图地址(LPVOID)是两个独立资源,漏关任意一个都会泄漏。
通过 SSH 隧道从 Android 设备在互联网上对 Windows PC 实现完整远程控制的设置与使用指南,适用于远程桌面访问、安全 RDP 等。
立即学习“C++免费学习笔记(深入)”;
- Linux 下
mmap失败返回MAP_FAILED(即(void*)-1),不是nullptr,判空时别写if (!ptr) - Windows 下
MapViewOfFile失败返回nullptr,但CreateFileMapping失败也返回nullptr,必须两级检查 - 映射起始偏移必须对齐:Linux 要求页对齐(通常 4096),Windows 同样要求
dwFileOffsetLow低 12 位为 0;非对齐偏移直接失败,不自动修正
只读场景下最容易被忽略的权限与生命周期问题
很多人以为“只读”就安全,结果在 Linux 上遇到 Permission denied,在 Windows 上遇到 ERROR_INVALID_PARAMETER,其实都和打开方式强相关。
- Linux:文件 open 时必须带
O_RDONLY,且底层文件系统需支持 mmap(某些 procfs 或 tmpfs 路径不支持) - Windows:
CreateFile的dwShareMode至少设为FILE_SHARE_READ,否则其他进程或同一进程后续打开会失败 - 映射后文件可被删除(Linux 行为),但 Windows 下若先删文件再访问映射区域,会触发
EXCEPTION_IN_PAGE_ERROR(相当于 segfault),无法 catch,只能靠提前校验 - 不要把
MappedView成员变量存成裸指针长期持有——文件关闭或 unmmap 后指针立刻失效,ASan 未必能捕获这种 use-after-unmap
简单示例:跨平台读取文件前 4KB
以下代码片段只展示核心路径,省略错误码转字符串等辅助逻辑:
// Linux
int fd = open("data.bin", O_RDONLY);
if (fd == -1) return;
void* ptr = mmap(nullptr, 4096, PROT_READ, MAP_PRIVATE, fd, 0);
if (ptr == MAP_FAILED) { close(fd); return; }
// 使用 ptr...
munmap(ptr, 4096); close(fd);
<p>// Windows
HANDLE hFile = CreateFileA("data.bin", GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE) return;
HANDLE hMap = CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, 4096, nullptr);
if (!hMap) { CloseHandle(hFile); return; }
void* ptr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 4096);
if (!ptr) { CloseHandle(hMap); CloseHandle(hFile); return; }
// 使用 ptr...
UnmapViewOfFile(ptr); CloseHandle(hMap); CloseHandle(hFile);真正麻烦的不是第一段映射,而是当你要支持任意 offset、size、自动探测文件大小、或 fallback 到 fread 时——那些边界判断和平台适配才开始咬人。别低估 lseek 和 GetFileSizeEx 的返回值符号差异,也别信“文件大小一定能被页整除”。

















