mat*_*t88 6 c unix linux posix mmap
当mmap()输入文本文件时,就像这样
int fd = open("file.txt", O_RDWR);
fstat(fd, &sb)
char *text = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Run Code Online (Sandbox Code Playgroud)
文件内容直接映射到内存中,并且text它不包含NUL终结符,因此使用普通字符串函数对其进行操作将不安全.在Linux(至少)上,未使用页面的剩余字节是零填充的,因此在文件大小不是页面大小的所有情况下,有效地获得NUL终止符.
但依赖于那种感觉很脏并且其他mmap()实现(例如,在FreeBSD中,我认为)不会填充部分页面.映射文件是页面大小的倍数也将缺少NUL终止符.
有合理的方法来解决这个问题或添加NUL终结器吗?
我考虑过的事情
strn*()专门使用函数并跟踪到缓冲区末尾的距离.
str*()功能没有strn*()对应物,比如strstr.str*()函数MAP_FIXED不是线程安全的; 无论如何,这似乎是一个可怕的黑客mmap()一个额外的字节并使地图可写,并写入NUL终结符.OpenGroup的mmap手册页说你可以制作比你的对象大小更大的映射,但是访问实际映射对象之外的数据会产生一个SIGBUS.
str*()函数SIGBUS,这可能意味着发生了其他事情.我真的不确定写NUL终结器会起作用吗?ftruncate()一个字节.
str*()函数; ftruncate()将为您分配一个NUL字节到新分配的区域mmap()不填充部分页面的实现的问题read()将文件放入某些malloc()内存并忘记了mmap()
malloc()NUL 易于和额外的字节mmap()解决方案#1似乎通常是最好的,只需要阅读文本功能的一些额外工作.
有更好的替代品,还是这些是最好的解决方案?我没有考虑过这些解决方案的某些方面是否会使它们或多或少具有吸引力?
我建议在这里进行范式转变。
您正在查看由定义文本的“\0”分隔字符串组成的整个宇宙。与其以这种方式看待世界,不如尝试看看文本被定义为由开始和结束迭代器定义的序列的世界。
您mmap的文件,然后最初设置开始迭代器,将其调用beg_iter到 mmap-ed 段的开头,并将结束迭代器调用 ,end_iter到 mmap-ed 段中最后一个字节后面的第一个字节,或者beg_iter+number_of_pages*pagesize,然后直到任何一个
A)end_iter等于beg_iter, 或
B)beg_iter[-1]不是空字符,那么
C) 递减end_iter,然后返回步骤 A。
完成后,您将拥有一对迭代器,即定义文本字符串的起始迭代器值和结束迭代器值。
当然,在这种情况下,您的迭代器是普通的char *,但这实际上并不是很重要。重要的是,现在您发现自己拥有 C++ 标准库中丰富的算法和模板可供您使用,它们可以让您实现许多复杂的操作,包括可变的(如 )和std::transform不可变的(如std::find)。
空终止字符串实际上是纯 C 时代的遗留物。对于 C++,空终止字符串有些过时且平凡。现代 C++ 代码应该使用std::string对象以及由开始和结束迭代器定义的序列。
一个小脚注:NULL您可能会发现在 mmap-ing() 之前更容易 fstat() 文件并获取文件的确切长度(以字节为单位),而不是计算最终 mmap-ing() 的填充量。然后您现在将确切地知道很多已映射,并且您不必通过查看填充来对其进行逆向工程。