为什么mapped_file :: data返回char *而不是void *

时间:2015-05-14 18:23:33

标签: c++ boost boost-iostreams

甚至更好的模板<T*>

如果内存映射文件包含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 :由于似乎很难达到目的而不是讨论天气,因此详细说明者的内存模型由比特,字节或单词组成,我将重新说明一个例子:

#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?

请回答有关奖励积分的所有问题:)

3 个答案:

答案 0 :(得分:2)

  

如果内存映射文件包含32位整数序列,如果data()返回void*,我们可以直接静态转换为std::uint32_t

不,不是真的。你仍然需要考虑(如果没有别的话)endianness。这个&#34;一步转换&#34;这个想法会让你陷入虚假的安全感。您忘记了文件中的字节与要进入程序的32位整数之间的整个转换层。即使翻译恰好是您现有系统和给定文件的无操作,它仍然是翻译步骤。

获得一个字节数组要好得多(字面意思是char*指向的!)然后你知道你必须做一些思考以确保你的指针转换有效,并且您正在执行其他所需的工作。

答案 1 :(得分:1)

char*表示原始字节数组,这是最常见情况下的mapped_file :: data。

void*会产生误导,因为它提供了有关所包含类型的更少信息,需要更多设置才能使用char* - 我们知道文件内容是一些字节,char*表示

模板返回类型需要在库内执行转换为该类型,而在调用者端执行此操作更有意义(因为库只提供原始文件内容的接口,并且调用者具体知道这些内容是什么是)。

答案 2 :(得分:0)

返回char *似乎只是boost::iostreams实施的(特殊)设计决策。

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

正如通过UNIX mmap规范(以及malloc)所观察到的那样,也使用void*

它有点与void* or char* for generic buffer representation?

重复

需要注意的是,当从一个架构写入内存并在另一个架构上读取时,可能需要Lightness在另一个答案中提到的翻译层。使用转换类型很容易解决字节顺序,但也需要考虑对齐

关于静态演员:http://en.cppreference.com/w/cpp/language/static_cast提到:

  

指向void(可能是cv-qualified)的类型指针的prvalue可以   转换为指向任何类型的指针。如果是原始指针的值   满足目标类型的对齐要求,然后是   结果指针值不变,否则未指定。   将任何指向指针的指针转换为void并返回指针指向   原始(或更多cv认证)类型保留其原始值。

因此,如果要进行内存映射的文件是在具有不同对齐的其他体系结构上创建的,则加载可能会失败(例如,使用SIGBUS),具体取决于体系结构和操作系统。