提问者:小点点

将布局映射到存储器地址


在C++中,有没有一种方法可以将我想要的布局“映射”到内存数据上,而不用进行内存复制?

即。 有一个void*buffer,我知道它的布局:

  • 字节1:uint8_t
  • 字节2-3:UINT16_T
  • 字节4:uint8_t

我知道我可以创建一个struct,并将数据memcpy到struct,然后我可以将值作为struct的字段。

但是,有没有一种不用抄袭就能做到这一点的方法呢? 数据已经在那里,我只需要得到一些字段,我正在寻找一种方式,为一些东西可以帮助与布局。

(我可以有一些static int用于内存偏移量,但我希望有一些更通用的)。

即:我会有更多的“布局”,并且基于原始数据的类型,我会映射适当的布局并访问其字段,这些字段仍然指向原始数据。

我知道我可以将结构指向数据,这很容易:

struct message {
    uint8_t type;
};
struct request:message {
    uint8_t rid;
    uint8_t other;
};
struct response:message {
    uint8_t result;
};

vector<uint8_t> data;
data.push_back(1); //type
data.push_back(10);
data.push_back(11);
data.push_back(12);
data.push_back(13);

struct request* ptrRequest;

ptrRequest = (struct request*)&data[1];
cout << (int)ptrRequest->rid; //10
cout << (int)ptrRequest->other; //11

但我想要实现的是有一个包含布局的地图,即:

map<int, struct message*> messagetypes;

但是我不知道如何才能继续,因为定位需要一个新的对象,而且如果地图只存储基本指针的话,施法也是很有挑战性的。


共2个答案

匿名用户

在C++中,有没有一种方法可以将我想要的布局“映射”到内存数据上,而不用进行内存复制?

不,不是在标准C++中。

如果布局与类1的布局匹配,那么您可能能够做的是首先将内存数据写入类实例,这样之后就不需要进行复制。

如果上述方法不可行,那么您可以将数据复制(是的,这是memcopy,但保持这种想法)到类的一个自动实例上,然后将自动实例的一个副本重新放置到源数组上。 一个好的优化者可以看到这些来回的拷贝不会改变值,并且可以把它们优化掉。 匹配布局在这里也是必要的。 示例:

struct data {
    std::uint8_t  byte;
    std::uint8_t  another;
    std::uint16_t properly_aligned;
};

void* buffer = get_some_buffer();
if (!std::align(alignof(data), sizeof(data), buffer, space))
    throw std::invalid_argument("bad alignment");

data local{};
std::memcpy(&local, buffer, sizeof local);
data* dataptr = new(buffer) data{local};
std::uint16_t value_from_offset = dataptr->properly_aligned;

https://godbolt.org/z/uvrxs2注意,在生成的程序集中没有调用std::memcpy

1然而,数据似乎不太可能匹配类的布局,因为第二个元素UINT16_T没有从布局开始对齐到两个16位边界。

匿名用户

如果您的布局结构是POD,您可以在不初始化的情况下执行placement new-expression,这将作为对象创建标记。 例如:

#include <new> // Placement new.
// ...
uint8_t* data = ...; // Read from disk, network, or elsewhere.
static_assert(std::is_pod<request>::value, "struct request must be POD.");
request* ptrRequest = new (static_cast<void*>(data)) request;

这只适用于豆荚。 这是在P0593R6隐式创建用于低级对象操作的对象中记录的一个长期存在的问题。

如果您的目标体系结构要求数据对齐,请添加data指针对齐检查。

另一个答案指出,memcpy可能被编译器删除,请检查程序集输出。