簡體   English   中英

如何解決從mmap()返回的字符串中缺少NUL終止符?

[英]How to work around lack of NUL terminator in strings returned from 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);

文件內容直接映射到內存中, text內容不包含NUL終結符,因此使用普通字符串函數對其進行操作將不安全。 在Linux(至少)上,未使用頁面的剩余字節是零填充的,因此在文件大小不是頁面大小的所有情況下,有效地獲得NUL終止符。

但依賴於它感覺很臟,其他mmap()實現(例如,在FreeBSD中,我認為)不會零填充部分頁面。 映射文件是頁面大小的倍數也將缺少NUL終止符。

有合理的方法來解決這個問題或添加NUL終結器嗎?

我考慮過的事情

  1. 僅使用strn*()函數並跟蹤到緩沖區末尾的距離。
    • 優點:不需要NUL終結器
    • 缺點:在解析文本時需要額外跟蹤以了解文件末尾的距離; 一些str*()函數沒有strn*()對應函數,比如strstr
  2. 如建議的另一個答案 ,請在映射文本文件后在固定地址進行匿名映射。
    • 優點:可以使用常規的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()
    • 優點:避免所有這些解決方案; 容易使用malloc()和NUL的額外字節
    • 缺點:與mmap()不同的性能特征

解決方案#1似乎通常是最好的,只需要在閱讀文本的功能方面做一些額外的工作。

有更好的替代品,還是這些是最好的解決方案? 我沒有考慮過這些解決方案的某些方面是否會使它們或多或少具有吸引力?

我建議在這里進行范式轉換。

您正在查看由定義文本的'\\ 0'分隔字符串組成的整個Universe。 不要以這種方式看世界,為什么不嘗試查看將文本定義為由開始和結束迭代器定義的序列的世界。

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()文件更容易fstat(),並且在mmap之前獲取文件的確切長度(以字節為單位),而不是計算出mmap-ing()的NULL填充量。 那么你現在確切地知道很多已經被mmaped,你不必通過查看填充來進行逆向工程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM