I have a void pointer called ptr. I want to increment this value by a number of bytes. Is there a way to do this?
Please note that I want to do this in-place without creating any more variables.
Could I do something like ptr = (void *)(++((char *) ptr)); ?
You cannot perform arithmetic on a void pointer because pointer arithmetic is defined in terms of the size of the pointed-to object.
You can, however, cast the pointer to a char*, do arithmetic on that pointer, and then convert it back to a void*:
void* p = /* get a pointer somehow */;
// In C++:
p = static_cast<char*>(p) + 1;
// In C:
p = (char*)p + 1;
No arithmeatic operations can be done on void pointer.
The compiler doesn't know the size of the item(s) the void pointer is pointing to. You can cast the pointer to (char *) to do so.
In gcc there is an extension which treats the size of a void as 1. so one can use arithematic on a void* to add an offset in bytes, but using it would yield non-portable code.
Just incrementing the void* does happen to work in gcc:
#include <stdlib.h>
#include <stdio.h>
int main() {
int i[] = { 23, 42 };
void* a = &i;
void* b = a + 4;
printf("%i\n", *((int*)b));
return 0;
}
It's conceptually (and officially) wrong though, so you want to make it explicit: cast it to char* and then back.
void* a = get_me_a_pointer();
void* b = (void*)((char*)a + some_number);
This makes it obvious that you're increasing by a number of bytes.
You can do:
++(*((char **)(&ptr)));
Related
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.
You can use reinterpret_cast to convert pointers other than void* to another pointers.
MallocMetadata *tmp = reinterpret_cast<MallocMetadata *> (static_cast<char *> (p) - 5);
Another choice is casting the char* after subtracting something to void* again.
MallocMetadata *tmp = static_cast<MallocMetadata *> (static_cast<void *> (static_cast<char *> (p) - 5));
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);
I don't know what you'll make of this, but I'll try:
There's a requirement in the standard that void * and character pointers have the same representation and alignment that falls out of C and how historically you had character pointer types where you now have void *.
If you have a void *, actually a void * and not some other type of pointer, and you wanted to advance it a byte at a time, you should be able to create a reference-to-pointer-to-unsigned-character bound to the pointer-to-void, as in:
auto &ucp = reinterpret_cast<unsigned char *&>(void_pointer);
And now it should be possible to manipulate void_pointer through operations on ucp reference.
So ++ucp will advance it, and therefore void_pointer, by one.
Consider the following situation.
I have a void * first pointing to a certain amount of memory. I have another void * second pointing to something else. I want to save void * second in the memory pointed by the first pointer.
My approach:
*(void**) first = second;
Is this valid? Are there any precautions to consider?
You can write anything you want to the memory location pointed by void* as long as:
It is large enough to hold that data type
It is sufficiently aligned for data type
Reads from that location consistent with writes
So, it's legal to do things like:
void* first = malloc(sizeof(void*));
*(void**)first = second;
....
void* another = *(void**)first; //Now another == second
But anything else, for example:
malloc(sizeof(int*)), or malloc(4)
void* first = &someCharArray[11]
int* another = *(int**)first
Is implementation defined at best. And sometimes undefined behavior.
That is exactly what void* type for - you cast some pointer to void*, then you cast back. You are responsible for types to match.
Try this
#include <string.h>
#include <stdlib.h>
int main()
{
int memory[10];
void *first = ( void * )memory;
void *second = ( void * )&memory[5];
*( int * )first = ( int )second;
return 0;
}
You can validate result in memory[0]
Version 1:
int* work(int** pointer, int offset)
{
return *pointer + (offset/sizeof(int));
}
int main()
{
int** pointer = (int**) 0x4df73c;
int offset = 0xf4;
int* healthLowestPointer = work(pointer, offset);
while(true) {
*healthLowestPointer = 1000;
Sleep(250);
}
}
Version 2:
int* work(int* pointer, int offset)
{
return (int*) (*pointer + (offset/sizeof(int)));
}
int main()
{
int* pointer = (int*) 0x4df73c;
int offset = 0xf4;
int* healthLowestPointer = work(pointer, offset);
while(true) {
*healthLowestPointer = 1000;
Sleep(250);
}
}
Version 1 works correctly, but version 2 doesn't seem to. I don't understand why version 2 is broken. Isn't dereferencing a a double-level pointer the same thing as dereferencing a single-level pointer i.e. it grabs the value at the memory address the pointer contains?
How would I write a function that takes a n-level pointer as input, and returns a 1-level pointer by dereferencing the n-level pointer n-1 times?
They are very different things. An int** is a pointer to a pointer to an int. If you dereference it, you get an int*. An int* is a pointer to an int. If you dereference it, you get an int.
In the first example, you pass an int** with value 0x4df73c as the first argument to work. You then dereference this, which should give you an int*. That is, 0x4df73c is the address of an address and doing *pointer has gotten you the second addess. You then do pointer arithmetic with this int* by adding (offset/sizeof(int)), which works out how many ints there are with offset bytes. So when you add this value, your int* will move along to point at the int at that offset. You then return this int* and all is well.
In the second example, you pass 0x4df73c as an int*. You then dereference it, which gives you an int. Now the + doesn't do pointer arithmetic - it does integer arithmetic. (offset/sizeof(int)) will still give you the number of ints in offset bytes, but the arithmetic won't do what you want. It won't increase the value of the int by the appropriate amount.
Let's say an int is 4 bytes on your machine. When you have an int* called p and you do p + 5, this doesn't just add 5 to the address in p. It adds 5 times the size of an int (20 bytes), so that it's now pointing at the 5th int. However, if you have an int called i and you do i + 5, this really does just add 5.
So that's your problem. When you add to the int, you're not doing the appropriate arithmetic. I imagine it would work if you change it to, assuming an int* and an int are the same size on your system (as you say they are):
return (int*) (*pointer + offset);
but I do not recommend this. Don't use an int as though it were a pointer. The cast to the (int*) involves a reinterpret_cast and is horrible. Stick to your first code.
Pointer arithmetic and integer arithmetic are not the same thing.
Ignoring the issue of whether writing to the locations you are using is valid, consider the result of these:
int i=5;
int j=i+1; // now j==6
int* pi = &i; // let's say pi is 0x1000
int* pj = &i+1 // now pj is 0x1000 + (sizeof int)
I know that converting a pointer to one int is unsafe, because the pointer can be bigger than the int in some architectures (for instance in x86_64).
But what about converting the pointer to several ints, an array of them? If the pointer size is 2 times bigger than int then convert pointer* to int[2].
The number of needed ints then is ceil(sizeof(pointer*)/sizeof(int)).
I need to do this because there is a function which takes ints as arguments and I want to pass a pointer to it.
Doesn't your platform provide a intptr_t ?
Fairly robust & portable:
void* p = foo();
std::vector<int> buf(sizeof(p));
std::copy(reinterpret_cast<char*>(&p),
reinterpret_cast<char*>(&p) + sizeof(p),
buf.begin());
What about something like this:
void *pointer = (void*) 0x0123456789ABCDEFULL;
// 4 int's max, I don't know how to do it in a generic way
assert(sizeof(pointer) <= 4*sizeof(int));
int buffer[4]; // copy from pointer to buffer
memcpy(buffer, &pointer, sizeof(pointer));
// call the function
f(buffer[0], buffer[1], buffer[2], buffer[3]);
// how to recover the value of the pointer
void f(int b0, int b1, int b2, int b3) {
int buffer[4] = {b0, b1, b2, b3};
void *pointer; // copy from buffer to pointer
memcpy(&pointer, buffer, sizeof(test_pointer));
}
I can't think of a reason to do it like that, but thats up to you :).
Usually you should not do that in a generic way, so what I'd do is, coding the 2 or 3 ways the pointer has to be transformed.
if( sizeof(pointer) == sizeof(int16) ) //or short
{
transformShortToInt(pointer);
}
else if( sizeof(pointer) == sizeof(Int32) )
{
(int)pointer;
}
else if( sizeof(pointer) == sizeof(Int64) )
{
int[2] ar = new int[2];
ar[0] = (int)(pointer & 0x0000FFFF);
ar[1] = (int)((pointer>>32) & 0x0000FFFF);
}
Although the generic code would also not be that complex.
edit: generic:
int arSize = sizeof(pointer)/sizeof(int);
if(arSize < 1)
{
arSize = 1;
}
int[] args = new int[arSize];
for( int i = 0; i < arSize; i++ )
{
args[i] = (int)((pointer>>(i*32))&0x0000FFFF);
}
although I did not test what happens with pointer >> 0 i guess it should work :).
Yet another solution:
#define BIG_ENOUGH 4
typedef union {
int buffer[BIG_ENOUGH];
pointer_t* pointer;
} proxy_t;
static_assert(sizeof(pointer_t*) <= BIG_ENOUGH*sizeof(int));
// before calling the function
proxy_t proxy;
proxy.pointer = the_pointer;
// call to the function, cannot be generic here
f(proxy.buffer[0], proxy.buffer[1], proxy.buffer[2], proxy.buffer[3]);
// how to recover the value of the pointer
void f(int b0, int b1, int b2, int b3) {
proxy_t proxy = { { b0, b1, b2, b3 } };
the_pointer = proxy.pointer;
}
if a function takes an array of ints, then yes you can manually detect the size of void* versus the size of int on your machine and save your pointer to array[0] + array[1], etc.
It's a bit hard to tell what's really needed from your description. What will the function do? Will you have to handle big/little-endian difference, for example?
I have macros for this:
#define DIM_ARR(arr) (sizeof(arr) / sizeof(arr[0]))
Even if array is empty - this construction (sizeof(arr[0])) resolved on compile time - that is why you will get correct size
you said you want to pass a pointer to a function with int as arguments.
If your pointer points to an integer or character or float you can always dereference it, caste it and pass by value.
Or, if you really want to pass by address, then modify the function definition to take pointer as argument.
Or, if you are using some library function then you are on the wrong way man.
And even you convert it to an array of ints, how are going to pass the array?, array are always passed by address.
In the following lines of code, I need to adjust the pointer pm by an offset in bytes in one of its fields. Is there an better/easier way to do this, than incessantly casting back and forth from char * and PartitionMap * such that the pointer arithmetic still works out?
PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;
For those that can't grok from the code, it's looping through variable length descriptors in a buffer that inherit from PartitionMap.
Also for those concerned, partitionMapLength always returns lengths that are supported by the system this runs on. The data I'm traversing conforms to the UDF specification.
I often use these templates for this:
template<typename T>
T *add_pointer(T *p, unsigned int n) {
return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + n);
}
template<typename T>
const T *add_pointer(const T *p, unsigned int n) {
return reinterpret_cast<const T *>(reinterpret_cast<const char *>(p) + n);
}
They maintain the type, but add single bytes to them, for example:
T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x
Casting is the only way, whether it's to a char* or intptr_t or other some such type, and then to your final type.
You can of course just keep two variables around: a char * to step through the buffer and a PartitionMap * to access it. Makes it a little clearer what's going on.
for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
ptr += pm->partitionMapLength;
pm = (PartitionMap *)ptr;
}
return pm;
As others have mentioned you need the casts, but you can hide the ugliness in a macro or function. However, one other thing to keep in mind is alignment requirements. On most processors you can't simply increment a pointer to a type by an arbitrary number of bytes and cast the result back into a pointer to the original type without problems accessing the struct through the new pointer due to misalignment.
One of the few architectures (even if it is about the most popular) that will let you get away with it is the x86 architecture. However, even if you're writing for Windows, you'll want to take this problem into account - Win64 does enforce alignment requirements.
So even accessing the partitionMapLength member through the pointer might crash your program.
You might be able to easily work around this problem using a compiler extension like __unaligned on Windows:
PartitionMap __unaliged *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
pm = (PartitionMap __unaligned *)(((char *)pm) + pm->partitionMapLength);
}
return pm;
Or you can copy the potentially unaligned data into a properly aligned struct:
PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
char* p = reinterpret_cast<char*>( pm);
ParititionMap tmpMap;
for ( ; index > 0 ; --index)
{
p += pm->partitionMapLength;
memcpy( &tmpMap, p, sizeof( newMap));
pm = &tmpMap;
}
// you may need a more spohisticated copy to return something useful
size_t siz = pm->partitionMapLength;
pm = reinterpret_cast<PartitionMap*>( malloc( siz));
if (pm) {
memcpy( pm, p, siz);
}
return pm;
The casting has to be done, but it makes the code nearly unreadable. For readability's sake, isolate it in a static inline function.
What is puzzling me is why you have 'partitionMapLength' in bytes?
Wouldn't it be better if it was in 'partitionMap' units since you anyway cast it?
PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here
Both C and C++ allow you to iterate through an array via pointers and ++:
#include <iostream>
int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
std::cout << *ptr << '\n';
++ptr;
}
For this to work, adding to pointers is defined to take the memory address stored in the pointer and then add the sizeof whatever the type is times the value being added. For instance, in our example ++ptr adds 1 * sizeof(int) to the memory address stored in ptr.
If you have a pointer to a type, and want to advance a particular number of bytes from that spot, the only way to do so is to cast to char* (because sizeof(char) is defined to be one).