2015-05-14 40 views
2

或者更好的模板<T*>爲什麼mapped_file :: data返回char *而不是void *

如果內存映射文件中包含的32個整數的序列,如果data()返回void*,我們才能夠在靜態澆鑄到std::uint32_t直接。

爲什麼助推作者選擇返回char*

編輯:正如指出的,如果可移植性是一個問題,需要翻譯。但是說一個文件(或者在這種情況下是一塊內存)是比字節流更多的比特流,IEEE754雙倍或者複雜的數據結構,在我看來這是一個非常廣泛的聲明,需要一些更多解釋。

即使具有與建議(和在這裏實現)會使代碼更具可讀性處理字節序,能夠直接映射到be_uint32_t向量:

struct be_uint32_t { 
    std::uint32_t raw; 
    operator std::uint32_t() { return ntohl(raw); } 
}; 

static_assert(sizeof(be_uint32_t)==4, "POD failed"); 

是否允許/建議投到be_uint32_t*?爲什麼或者爲什麼不?

應該使用哪種類型的演員?

EDIT2:因爲它似乎很難得到的地步,而不是在討論天氣的elaborator的內存模型由位,字節或字我會重組給予一個例子:

#include <cstdint> 
#include <memory> 
#include <vector> 
#include <iostream> 
#include <boost/iostreams/device/mapped_file.hpp> 

struct entry { 
    std::uint32_t a; 
    std::uint64_t b; 
} __attribute__((packed)); /* compiler specific, but supported 
           in other ways by all major compilers */ 

static_assert(sizeof(entry) == 12, "entry: Struct size mismatch"); 
static_assert(offsetof(entry, a) == 0, "entry: Invalid offset for a"); 
static_assert(offsetof(entry, b) == 4, "entry: Invalid offset for b"); 

int main(void) { 
    boost::iostreams::mapped_file_source mmap("map"); 
    assert(mmap.is_open()); 
    const entry* data_begin = reinterpret_cast<const entry*>(mmap.data()); 
    const entry* data_end = data_begin + mmap.size()/sizeof(entry); 
    for(const entry* ii=data_begin; ii!=data_end; ++ii) 
    std::cout << std::hex << ii->a << " " << ii->b << std::endl; 
    return 0; 
} 

鑑於map文件包含正確順序的位,是否有其他理由避免使用reinterpret_cast來使用我的虛擬內存而不先複製它?

如果沒有,爲什麼強制用戶通過返回類型指針來執行reinterpret_cast?

請回答加分所有的問題:)

+1

你可以使用'reinterpret_cast' ... – Brian

+0

'void'不算什麼。解除引用無用。 Mmaps不是無用的 – sehe

+0

@sehe:void僅僅意味着:「我不知道我指的是什麼,請確保在訪問數據之前進行操作!」。對我來說,比確定它指向字節更有意義,即使它確實指向小端32位整數! – baol

回答

0

返回char *似乎只是boost::iostreams實現的(特殊)設計決定。

其他API,例如, boost interprocess返回void*

正如通過UNIX mmap規範(和malloc)所觀察到的,也使用void*

這是有點的void* or char* for generic buffer representation?

副本作爲一個值得注意的問題時,內存從一個架構編寫的,並在不同的閱讀一個可能需要通過亮度在另一個答覆中提到翻譯層。字節順序很容易使用轉換類型來解決,但也需要考慮對齊

關於靜態鑄造:http://en.cppreference.com/w/cpp/language/static_cast提到:

類型的指針甲prvalue排尿(可能CV-合格)可以是 轉換爲指針的任何類型。如果原始指針 的值滿足目標類型的對齊要求,則結果指針值不變,否則不指定。 將指針指向void的任何指針並將其轉換爲指向 的指針原始(或更多cv-qualified)類型保留其原始值。

因此,如果需要內存映射的文件是在具有不同對齊的不同架構上創建的,則根據架構和操作系統的不同,加載可能會失敗(例如,使用SIGBUS)。

1

char*代表原始字節,也就是將mapped_file ::數據是最常見的情況是什麼的陣列。

void*會產生誤導,因爲它提供了有關所包含的類型較少的信息,並且需要更多的設置與當時char*工作 - 我們知道文件的內容是一些字節,這char*代表。

模板返回類型將需要在庫中執行該類型的轉換,而在調用方執行該操作更有意義(因爲庫僅提供原始文件內容的接口,並且調用者明確知道那些內容內容是)。

+0

但是如果我的映射文件包含字節以外的東西呢?你是否看到需要將字節複製到我的數據結構中,而不是簡單地轉換爲我需要的內容? (假設我對文件有控制權,並且不需要將文件移植到不同的體系結構上) – baol

+0

「如果我的映射文件包含除字節以外的內容會怎樣?」我不知道計算機中的任何內容不是由字節。你什麼意思? – edmz

+0

@black我的意思是說,一個字節是對包含數據的假設,與其他任何其他數據一樣有效。我可以肯定地知道我的文件是一個半字節數組!這是澄清嗎? – baol

2

如果映射文件存儲器包含的32個整數的序列,如果data()返回void*,我們才能夠在靜態澆鑄到std::uint32_t直接。

不,不是真的。你仍然必須考慮(如果沒有別的)排序。這種「一步轉換」的想法會讓你陷入一種錯誤的安全感。您忘記了文件中的字節與想要加入程序的32位整數之間的整個轉換層。即使這種翻譯在您現在的系統和給定的文件中碰巧是無用的,它仍然是一個翻譯步驟。

這是更好的獲得字節數組(字面什麼char*點!),那麼你知道你必須做一些思考,以確保您的指針轉換是有效的,並且要執行任何其他工作需要。

+1

對於字節順序,我建議創建一個類似'le_uint32_t'的類,它們具有'uint32_t'轉換和'operator =',但是避免使用構造函數,或者現在需要在C++ 11中維護PODness。 –

+0

不確定字符是否可以保證是一個字節。在我看來,從翻譯的角度來看,char *可能比虛空更具誤導性。 (順便說一句:你指出了錯誤的安全感,請注意它對所有未經測試的軟件都是常見的:) – baol

+0

在一般情況下,你建議將字節複製到目標數據結構中,以保持它們一個一個在正確的位置,而不是直接映射到一個壓縮結構?正如Zan所建議的那樣,而不是解決排序問題? – baol

相關問題