如何推进 void * 指针? [英] How to Advance void * pointer?

查看:72
本文介绍了如何推进 void * 指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 C++ 中我有:

MallocMetadata *tmp = static_cast(p);

但现在我希望 tmp 在内存中之前是 5 个字节,所以我尝试了:

MallocMetadata *tmp = static_cast(p-5);

但这并没有编译通过,我阅读了一些建议这样做的文章(并且也不起作用):

MallocMetadata *tmp = static_cast(static_cast(p) - 5);

如何解决这个问题,请注意:我确定内存中的位置是合法的,而且我希望 tmp 的类型为 MallocMetadata* 以便稍后使用.

解决方案

C++ 如何推进 void * 指针?

不可能推进 void*.

将指针前移一个修改指针以指向对象数组中先前指向的对象的下一个同级.数组的两个元素之间的距离在不同类型的对象之间是不同的.距离与物体的大小完全相同.

因此要推进指针,必须知道所指向对象的大小.void* 可以指向任意大小的对象,并且无法从指针中获取有关该大小的信息.

您可以做的是将 void* 静态转换为指向对象的动态类型.只要类型是完整的,就可以通过知道指针的类型来知道所指向对象的大小.然后,您可以使用指针算术将转换后的指针推进到指向对象的同级对象.

<块引用>

但现在我希望 tmp 在内存中之前为 5 个字节

在我们继续之前,我想明确指出这是一种不安全的尝试,您必须详细了解语言规则才能有机会正确执行此操作.我敦促您考虑是否有必要这样做.

要得到一个指向前5个字节的内存地址的指针,可以将void*static_castunsigned char*,并对转换后的指针进行指针运算:

static_cast(p) - 5


<块引用>

MallocMetadata *tmp = static_cast(static_cast(p) - 5);

char* 不能静态转换为任意对象指针类型.如果内存地址正确对齐((地址包含类似类型的对象)或(MallocMetadata是一个简单的类型,地址不包含其他类型的对象,并且您将写入该地址而不是读取,从而创建一个新对象)),那么您可以改用 reinterpret_cast :

MallocMetadata *tmp = reinterpret_cast(static_cast(p) - 5);

一个完整的例子:

//准备整数偏移= 5;std::size_t 填充 = sizeof(MallocMetadata) >= 偏移量?0: sizeof(MallocMetadata) - 偏移量;自动对齐 = static_cast(alignof(MallocMetadata));void* p_storage = ::operator new(sizeof(MallocMetadata) + padding, align);MallocMetadata* p_mm = new (p_storage) MallocMetadata{};void* p = reinterpret_cast(p_mm) + 偏移量;//和上面一样MallocMetadata *tmp = reinterpret_cast(static_cast(p) - 偏移量);//清理tmp->~MallocMetadata();::操作员删除(tmp);

In C++ I had:

MallocMetadata *tmp = static_cast<MallocMetadata *> (p);

But now I want tmp to be 5 bytes before in memory so I tried:

MallocMetadata *tmp = static_cast<MallocMetadata *> (p-5);

But that didn't compile, I read some articles which suggested this (and didn't work too):

MallocMetadata *tmp = static_cast<MallocMetadata *> (static_cast<char *> (p) - 5);

How to fix this problem, please note: I am sure that place in memory is legal plus I want tmp to be of type MallocMetadata* to use it later.

解决方案

C++ How to Advance void * pointer?

It is not possible to advance a void*.

Advancing a pointer by one modifies the pointer to point to the next sibling of the previously pointed object within an array of objects. The distance between two elements of an array differs between objects of different types. The distance is exactly the same as the size of the object.

Thus to advance a pointer, it is necessary to know the size of the pointed object. void* can point to an object of any size, and there is no way to get information about that size from the pointer.

What you can do instead is static cast void* to the dynamic type of the pointed object. The size of the pointed object is then known by virtue of knowing the type of the pointer, as long as the type is complete. You can then use pointer arithmetic to advance the converted pointer to a sibling of the pointed object.

But now I want tmp to be 5 bytes before in memory

Before we proceed any further, I want to make it clear that this is an unsafe thing to attempt, and you must know the language rules in detail to have even a remote chance of doing this correctly. I urge you to consider whether doing this is necessary.

To get a pointer to the memory address 5 bytes before, you can static_cast void* to unsigned char* and do pointer arithmetic on the converted pointer:

static_cast<unsigned char*>(p) - 5


MallocMetadata *tmp = static_cast<MallocMetadata *> (static_cast<char *> (p) - 5);

char* isn't static-castable to arbitrary object pointer types. if the memory address is properly aligned and ((the address contains an object of similar type) or (MallocMetadata is a trivial type and the address doesn't contain an object of another type and you're going to write to the address and not read, thereby creating a new object)), then you can use reinterpret_cast instead:

MallocMetadata *tmp = reinterpret_cast<MallocMetadata*>(
    static_cast<char*>(p) - 5
);

A full example:

// preparation
int offset = 5;
std::size_t padding = sizeof(MallocMetadata) >= offset
    ? 0
    : sizeof(MallocMetadata) - offset;
auto align = static_cast<std::align_val_t>(alignof(MallocMetadata));
void* p_storage = ::operator new(sizeof(MallocMetadata) + padding, align);
MallocMetadata* p_mm = new (p_storage) MallocMetadata{};
void* p = reinterpret_cast<char*>(p_mm) + offset;

// same as above
MallocMetadata *tmp = reinterpret_cast<MallocMetadata*>(
    static_cast<char*>(p) - offset
);

// cleanup
tmp->~MallocMetadata();
::operator delete(tmp);

这篇关于如何推进 void * 指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆