如何在C++内存映射文件的Disc结构体中用原生数组实现字符串列表
内存映射文件中共享字符串列表的原生数组实现方案
由于std::list<std::string>依赖堆内存指针,无法直接用于跨进程内存映射共享,我们可以通过固定大小数组或偏移量动态存储两种原生内存方式实现字符串列表的共享,以下是具体实现:
方案一:固定数量+固定长度的字符串数组(适合需求明确场景)
这种方式直接在Disc结构体中嵌入二维字符数组,内存连续且大小固定,实现最简单,适合字符串数量和单串长度可提前预估的场景。
修改后的结构体定义
#define MAX_SHARED_STRINGS 100 // 最大支持的字符串数量 #define MAX_STRING_LENGTH 1024 // 单个字符串的最大长度(含终止符) struct Disc { char cName[1024]; DWORD dSize; DWORD stringCount; // 实际存储的字符串数量 char strList[MAX_SHARED_STRINGS][MAX_STRING_LENGTH]; // 字符串列表 };
创建内存映射与写入数据
// 创建内存映射文件,大小直接用结构体总大小 HANDLE m_mmf = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Disc), "Disc_mmf"); if (m_mmf != NULL) { // 映射到当前进程地址空间 Disc* pDisc = (Disc*)MapViewOfFile(m_mmf, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (pDisc != NULL) { // 填充基础字段 strcpy_s(pDisc->cName, "SystemDisc"); pDisc->dSize = 1024 * 1024 * 512; // 写入字符串列表 pDisc->stringCount = 3; strcpy_s(pDisc->strList[0], "User Document"); strcpy_s(pDisc->strList[1], "System Log"); strcpy_s(pDisc->strList[2], "Temporary Files"); // 用完记得解除映射 UnmapViewOfFile(pDisc); } }
其他进程读取数据
HANDLE m_mmf = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "Disc_mmf"); if (m_mmf != NULL) { Disc* pDisc = (Disc*)MapViewOfFile(m_mmf, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (pDisc != NULL) { // 遍历读取字符串 for (DWORD i = 0; i < pDisc->stringCount; ++i) { printf("Shared String %d: %s\n", i+1, pDisc->strList[i]); } UnmapViewOfFile(pDisc); } }
方案二:偏移量动态存储(适合灵活场景)
如果字符串数量或长度不确定,可以通过记录相对偏移量的方式,将字符串内容存储在结构体之后的连续内存中,避免固定数组的限制。
修改后的结构体定义
#define MAX_SHARED_ENTRIES 100 // 最大支持的字符串条目数 // 记录单个字符串的偏移和长度 struct StringEntry { DWORD offset; // 相对于Disc结构体起始地址的偏移量 DWORD length; // 字符串长度(不含终止符) }; struct Disc { char cName[1024]; DWORD dSize; DWORD stringCount; // 实际存储的字符串数量 StringEntry entries[MAX_SHARED_ENTRIES]; // 字符串条目列表 // 字符串内容将紧跟在结构体之后的内存区域 };
创建内存映射与写入数据
// 待共享的字符串列表 const char* sharedStrings[] = {"Large File Archive", "Configuration Backup", "Cache Data", "User Preference"}; DWORD stringCount = _countof(sharedStrings); // 计算所有字符串的总内存(含终止符) DWORD totalStringSize = 0; for (DWORD i = 0; i < stringCount; ++i) { totalStringSize += strlen(sharedStrings[i]) + 1; } // 内存映射总大小 = 结构体大小 + 字符串总大小 DWORD totalMapSize = sizeof(Disc) + totalStringSize; HANDLE m_mmf = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, totalMapSize, "Disc_mmf"); if (m_mmf != NULL) { Disc* pDisc = (Disc*)MapViewOfFile(m_mmf, FILE_MAP_ALL_ACCESS, 0, 0, totalMapSize); if (pDisc != NULL) { // 填充基础字段 strcpy_s(pDisc->cName, "DataDisc"); pDisc->dSize = 1024 * 1024 * 1024; pDisc->stringCount = stringCount; // 字符串存储的起始地址:结构体末尾 char* pStringBuffer = (char*)pDisc + sizeof(Disc); DWORD currentOffset = sizeof(Disc); // 写入每个字符串并记录偏移 for (DWORD i = 0; i < stringCount; ++i) { const char* str = sharedStrings[i]; DWORD strLen = strlen(str); // 复制字符串到映射内存 strcpy_s(pStringBuffer, strLen + 1, str); // 记录偏移和长度 pDisc->entries[i].offset = currentOffset; pDisc->entries[i].length = strLen; // 更新缓冲区指针和偏移 pStringBuffer += strLen + 1; currentOffset += strLen + 1; } UnmapViewOfFile(pDisc); } }
其他进程读取数据
HANDLE m_mmf = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "Disc_mmf"); if (m_mmf != NULL) { Disc* pDisc = (Disc*)MapViewOfFile(m_mmf, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (pDisc != NULL) { for (DWORD i = 0; i < pDisc->stringCount; ++i) { StringEntry& entry = pDisc->entries[i]; // 通过偏移计算字符串地址:结构体起始地址 + 偏移量 char* str = (char*)pDisc + entry.offset; printf("Shared String %d (length: %d): %s\n", i+1, entry.length, str); } UnmapViewOfFile(pDisc); } }
关键注意事项
- 同步机制:跨进程访问时必须加同步锁(如
CreateMutex创建互斥量),避免并发读写导致数据损坏。 - 避免指针:绝对不能在映射内存中存储指针,不同进程的虚拟地址空间不同,指针会失效,必须用相对偏移量或固定数组。
- 内存大小:动态方案需要提前计算总内存,若需后续动态添加字符串,可创建一个足够大的预留映射空间,同时记录已使用的内存位置。
- 字符串编码:统一使用ANSI或UTF-8编码,避免跨进程编码不一致问题。
内容的提问来源于stack exchange,提问作者sbg123
相关产品推荐
相关产品推荐

