如何解决从mmap()返回的string中缺lessNUL终止符?

mmap()一个文本文件,像这样

int fd = open("file.txt", O_RDWR); fstat(fd, &sb) char *text = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 

文件内容直接映射到内存中,而text不包含NUL终止符,因此使用普通string函数对其进行操作将不安全。 在Linux上(至less)未使用页面的剩余字节是零填充的,所以在文件大小不是页面大小的倍数的所有情况下,您都可以得到一个NUL终止符。

但是依靠这种感觉,不要使用其他的mmap()实现(例如在FreeBSD中,我认为)不要零填充部分页面。 映射页面大小倍数的文件也将缺lessNUL终止符。

有没有合理的方法来解决这个问题或添加NUL终结符?

我考虑过的事情

  1. 独占使用strn*()函数并跟踪到缓冲区末尾的距离。
    • 优点:不需要NUL终结者
    • 缺点:在parsing文本时需要额外的跟踪以了解到文件结束的距离; 有些str*()函数没有strn*()对应,就像strstr
  2. 作为另一个答案build议,在你的文本文件的映射后,在一个固定的地址做一个匿名映射。
    • 优点:可以使用常规的C str*()函数
    • 缺点:使用MAP_FIXED不是线程安全的; 无论如何,这似乎是一个可怕的黑客
  3. mmap()一个额外的字节,并使地图可写,并写入NUL终止符。 OpenGroup的mmap手册页说,你可以使映射大于对象的大小,但访问实际映射对象之外的数据将生成一个SIGBUS
    • 优点:可以使用常规的C str*()函数
    • 缺点:需要处理(忽略?) SIGBUS ,这可能意味着发生了其他事情。 我不确定编写NUL终结符会起作用吗?
  4. 使用ftruncate()大小为页面大小倍数的文件扩展一个字节。
    • 优点:可以使用常规的C str*()函数; ftruncate()会将NUL字节写入新分配的区域
    • 缺点:我们必须写文件,这在所有情况下都是不可能的或不可接受的。 对于不填充部分页面的mmap()实现不解决问题
  5. read()文件到一些malloc()的内存,忘记了mmap()
    • 优点:避免所有这些解决scheme; 易于malloc()和NUL的额外字节
    • 缺点:与mmap()不同的性能特征

解决scheme#1似乎通常是最好的,只需要阅读文本的function部分额外的工作。

有更好的select,还是这是最好的解决scheme? 我没有考虑过这些解决scheme的一些方面,使它们或多或less有吸引力?

我建议在这里进行一个范式转变。

你正在看整个由'\ 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对象,以及由开始和结束迭代器定义的序列。

一个小脚注:你可能会发现fstat()文件更容易,并且在mmap-in之前获取文件的准确长度(以字节为单位),而不是计算出mmap-ing()的NULL填充量。 那么你现在就完全知道了很多东西,而且你不必通过查看填充来反向工程。