C 是否可以使用mmap仅映射文件的一部分?

C 是否可以使用mmap仅映射文件的一部分?,c,memory,pointers,memory-management,memory-mapped-files,C,Memory,Pointers,Memory Management,Memory Mapped Files,我有一个输入文件,其标题如下: P6\n width\n height\n depth\n 然后一个结构被写入这个文件,这个文件将被映射 因此,我想跳过标题,让我的mmap函数将ptr返回到该结构。我该怎么做?也许是和莱塞克?你能举例说明吗 我将在此处留下部分代码: printf("Saving header to output file\n"); if (writeImageHeader(h, fpout) == -1) { printf("Could not wri

我有一个输入文件,其标题如下:

P6\n
width\n
height\n
depth\n
然后一个结构被写入这个文件,这个文件将被映射

因此,我想跳过标题,让我的mmap函数将ptr返回到该结构。我该怎么做?也许是和莱塞克?你能举例说明吗

我将在此处留下部分代码:

printf("Saving header to output file\n");
    if (writeImageHeader(h, fpout) == -1) {
        printf("Could not write to output file\n");
        return -1;
    }

    last_index = (int)ftell(fpout);
    //printf("offset after header= %d\n",last_index);

    //alloc mem space for one row (width * size of one pixel struct)
    row = malloc(h->width * sizeof (pixel));

    /*Create a copy of the original image to the output file, which will be inverted*/
    printf("Starting work\n");
    for (i = 0; i < h->height; i++) {
        printf("Reading row... ");
        if (getImageRow(h->width, row, fpin) == -1) {
            printf("Error while reading row\n");
        }
        printf("Got row %d || ", (i + 1));

        printf("Saving row... ");
        if (writeRow(h->width, row, fpout) == -1) {
            printf("Error while reading row\n");
        }
        printf("Done\n");
    }


    /*Open file descriptor of the ouput file.
     * O_RDWR -  Read and Write operations both permitted
     * O_CREAT - Create file if it doesn't already exist
     * O_TRUNC - Delete existing contents of file*/
    if ((fdout = open(argv[2], O_RDWR, FILE_MODE)) < 0) {
        fprintf(stderr, "Can't create %s for writing\n", argv[2]);
        exit(1);
    }

    /*Get size of the output file*/
    if (fstat(fdout, &sbuf) == -1) {
        perror("Stat error ---------->\n");
        exit(1);
    }
    //printf("Size of output file: %d\n",(int)sbuf.st_size);

    /*Maps output file to memory*/
    if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0)) == (caddr_t) (-1)) {
        perror("Error mmaping");
        exit(EXIT_FAILURE);
    }
printf(“将头保存到输出文件\n”);
if(writeImageHeader(h,fpout)=-1){
printf(“无法写入输出文件\n”);
返回-1;
}
最后指数=(int)ftell(fpout);
//printf(“头后的偏移量=%d\n”,最后的索引);
//一行的alloc mem空间(宽度*一个像素结构的大小)
行=malloc(h->宽度*大小(像素));
/*创建原始图像到输出文件的副本,输出文件将被反转*/
printf(“开始工作”);
对于(i=0;iheight;i++){
printf(“阅读行…”);
如果(getImageRow(h->width,row,fpin)=-1){
printf(“读取行时出错\n”);
}
printf(“获取第%d行,(i+1));
printf(“保存行…”);
if(writeRow(h->宽度,行,fpout)=-1){
printf(“读取行时出错\n”);
}
printf(“完成”\n);
}
/*打开输出文件的文件描述符。
*O_RDWR-允许读写操作
*O_Create-如果文件不存在,则创建文件
*O_TRUNC-删除文件的现有内容*/
如果((fdout=open(argv[2],O_RDWR,文件模式))<0){
fprintf(stderr,“无法创建%s进行写入”,argv[2]);
出口(1);
}
/*获取输出文件的大小*/
如果(fstat(fdout和sbuf)=-1){
perror(“统计错误------->\n”);
出口(1);
}
//printf(“输出文件的大小:%d\n”,(int)sbuf.st_Size);
/*将输出文件映射到内存*/
如果((数据=mmap((caddr_t)0,sbuf.st_大小,PROT_读取,PROT_写入,MAP_共享,fdout,0))==(caddr_t)(-1)){
perror(“错误提示”);
退出(退出失败);
}
如您所见,现在我的ppm图像映射到
char*
数据,但我想跳过标题,只映射到
pixel*
部分

下面是我的代码,建议使用两个指针,一个来自mmap的char*和另一个等于+offset





嗯,您注意到您提供的“offset”参数为零吗?假设您知道所需的绝对偏移量,则将其传递。

如果您阅读
mmap
的手册页,您将发现其最终参数是
off\t offset
。说明:

。。。从字节偏移量“offset”开始,继续或最多从“fd”描述的对象映射“len”字节


我怀疑如果你把你的偏移量作为参数传入,它会做你想做的事。

如果你需要跳过的量小于系统页面大小,你就不能,因为在某些系统上,偏移量必须是页面大小的倍数。

那么,据我所知,我可以这样做吗

off_t offset_after_header = lseek(fdout, last_index, SEEK_SET);
    printf("Pointer is on %d\n",(int)offset_after_header);
    /*Maps output file to memory*/
    if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, offset_after_header)) == (caddr_t) (-1)) {
        perror("Error mmaping");
        exit(EXIT_FAILURE);
    }
这样,我就可以将文件映射到我想要的任何类型,在本例中是
pixel*


如果这样可以,我应该注意什么?例如,就像Ignacio Vazquez Abrams所说的那样,你只需要保留两个指针,一个指向
mmap
'd块开始的指针,另一个指向你想要的数据开始的指针。例如:

unsigned char *block = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0);
unsigned char *data = block + offset;

其中,
offset
是文件中到所需数据的偏移量。

至少在我的系统上,它说
如果offset或len不是pagesize的倍数,映射区域可能会超出指定范围。
这意味着它应该工作,但它确实值得检查。@Steven:它说偏移量必须是sysconf返回的页面大小的倍数(_SC_page_size)。这里。我想我的mmap比你的更令人敬畏:-p我希望这种不兼容能被更好地记录。@Steven:没有什么“令人敬畏的”关于一个
mmap
实现,它以静默方式无法共享实际缓存页。这可能会导致各种同步错误/竞争条件,至少会浪费大量内存。@R:我(我想!)显然是在开玩笑。我希望,如果性能降低,将记录在案,但并非我所有的希望都实现了…为什么不使用一点指针算法和一个指针变量呢?请注意,
caddr\u t
是前ANSI C的遗留废话。与
mmap
一起使用的类型是
void*
@R…:那么我如何以正确的方式调用mmap呢?这来自一个教师示例,LOL你可以在这里找到
mmap
的正确原型和用法:如果你的老师试图“纠正”你并坚持写
caddr\t
废话,可能会有用。除非偏移量是4096的倍数(或机器的页面大小)。你能举例说明吗?我不明白。。。在这上面花了太多时间。对不起,那数据是映射的实际部分吗?我可以用pixel*代替char*对吗?你真的需要把你的初始指针算法当作
char
指针,因为偏移量是以字节为单位的,而不是更大的类型。获得数据指针后,您可以将其强制转换为任何其他类型(只要它适合于访问该类型)。我不知道。我试过了,我的图像倒过来了,但它的左侧仍然有垃圾……该死!如果你们中的一些人能看到并尝试,我会留下我当前的代码…请?