将布局映射到内存地址

Map a layout onto memory address

本文关键字:内存 地址 映射 布局      更新时间:2023-10-16

C++有没有办法将我想要的布局"映射"到内存数据上,而无需复制它?

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

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

我知道我可以创建一个结构,并将数据内存到结构中,然后我可以将值作为结构的字段。

但是有没有办法在不复制的情况下实现这一目标?数据已经存在,我只需要获取一些字段,我正在寻找一种可以帮助布局的方法。

(我可以有一些内存偏移的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;

但是我不知道如何进行,因为放置需要一个新对象,如果地图仅存储基本指针,则铸造也具有挑战性。

如果您的布局结构是 POD,您可以在不进行初始化的情况下执行放置新表达式,作为对象创建标记。 例如:

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

这仅适用于 POD。这是P0593R6中记录的长期问题 隐式创建用于低级对象操作的对象。

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


正如另一个答案所述,memcpy编译器可能会消除,请检查程序集输出。

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的调用。

这里要考虑的一件事是,多字节整数必须与 CPU 本机使用的字节顺序相同。因此,数据不能跨系统(具有不同的字节字节数(移植。可移植性需要更高级的反序列化。


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