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