You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C与Python基于mmap实现共享映射文件读写的问题及解决方案

如何用Python向C创建的共享内存映射写入长字符串?

问题概述

你需要实现这样的场景:由C程序创建共享映射文件,Python程序向其中写入长字符串,供C程序读取。但在尝试过程中遇到了两个关键报错:

  • 首次尝试时Python抛出 IndexError: mmap assignment must be single-character string,且C程序只能读取到初始字符"1"
  • 尝试写入两个字符串时又出现 IndexError: mmap slice assignment is wrong size

问题根源

  • 第一个错误:你最初的Python代码里用 mm[0] = "01",这违反了mmap的规则——单个索引位置只能赋值单字符字符串,不能直接写入多字符内容。
  • 第二个错误:使用 sys.getsizeof() 计算字符串大小是错误的,这个函数返回的是Python字符串对象的总内存占用(包含额外的对象开销),而非字符串实际的字节长度。同时,最初的映射文件尺寸太小,也会导致写入时的尺寸不匹配问题。

修正后的可运行代码

在Sam Mason的帮助下,我们得到了可以正常工作的C和Python代码:

C程序(创建共享映射并读取内容)

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    int fd = open("hello.txt", O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("unable to open");
        return 1;
    }
    
    // 将文件大小设置为4096字节(标准内存页大小,确保有足够空间存储长字符串)
    if (ftruncate(fd, 4096) < 0) {
        perror("unable to set length");
        return 1;
    }
    
    // 创建共享内存映射,先赋予读写权限用于初始化
    char *shared = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (shared == MAP_FAILED) {
        perror("mmap failed");
        close(fd);
        return 1;
    }
    
    // 调用Python脚本写入内容
    system("python3 mappalo.py");
    
    // 读取并打印共享内存中的字符串
    printf("C CODE: %s\n", shared);
    
    // 释放映射和文件描述符
    munmap(shared, 4096);
    close(fd);
    return 0;
}

Python程序(向共享映射写入长字符串)

import mmap
import struct

with open('hello.txt', 'r+b') as fd:
    # 创建对应大小的内存映射
    buf = mmap.mmap(fd.fileno(), 4096, access=mmap.ACCESS_DEFAULT)
    
    arr = bytes("Hello123;", 'utf-8')
    arr1 = bytes("Hello412;", 'utf-8')
    
    # 用len()获取字节串的实际长度,而非sys.getsizeof()
    size = len(arr) + len(arr1)
    # 构造struct格式字符串,比如两个8字节字符串对应"8s8s"
    types = f"{len(arr)}s{len(arr1)}s"
    
    # 打包字符串后批量写入映射区域
    buf[:size] = struct.pack(types, arr1, arr)
    
    buf.close()

核心改进说明

  1. 固定映射文件大小:C程序中通过 ftruncate 将文件设置为4096字节(标准内存页大小),确保有足够空间存储长字符串,避免写入时超出范围。
  2. 正确计算字节长度:使用 len() 获取字节串的真实长度,避免了 sys.getsizeof() 带来的对象额外开销导致的尺寸不匹配。
  3. 批量写入方式:通过 struct.pack 将多个字符串打包成字节流,再通过切片赋值写入mmap,避开了单个字符赋值的限制。
  4. 资源清理:添加 munmap 和 close 操作,正确释放内存映射和文件描述符,防止资源泄漏。

内容的提问来源于stack exchange,提问作者giupardeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:04:15