[英]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終結器嗎?
我考慮過的事情
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'分隔字符串組成的整個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.