将布局映射到内存地址
Map a layout onto memory address
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 位边界。
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 为什么 vector 的随机访问迭代器给出与指针不同的内存地址?
- 使用内存地址访问结构的属性值
- 为什么C++总是显示十六进制内存地址,而不仅仅是整数?
- 将布局映射到内存地址
- 为什么同一个变量的内存地址不同?
- 无法将内存地址转换为值
- 给定特定内存地址的数组的动态内存分配
- 在 Microsoft Access SQL 中调用自定义 DLL 函数时传递的内存地址无效
- 获取 R 数据帧的内存地址
- c++ 编译器是否保护常量内存地址免受任何更改?
- 如何防止矢量的内存地址更改
- cout 打印内存地址而不是值
- 如何运行外部程序,向其传递内存地址以读取/写入?
- 循环中的变量被设置为下一个数组的元素始终具有相同的内存地址?
- 重载 ostream << 运算符,指针作为参数,导致输出上的内存地址
- C++在变量的内存地址上做什么来"deallocate"它?
- 在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法
- 为什么我无法获取 MSVS2019 / C++ 中字符或uint8_t变量的内存地址?