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.
Related
This question already has answers here:
C sizeof a passed array [duplicate]
(7 answers)
Closed 4 years ago.
In the program below the length of the array ar is correct in main but in temp it shows the length of the pointer to ar which on my computer is 2 (in units of sizeof(int)).
#include <stdio.h>
void temp(int ar[]) // this could also be declared as `int *ar`
{
printf("%d\n", (int) sizeof(ar)/sizeof(int));
}
int main(void)
{
int ar[]={1,2,3};
printf("%d\n", (int) sizeof(ar)/sizeof(int));
temp(ar);
return 0;
}
I wanted to know how I should define the function so the length of the array is read correctly in the function.
There is no 'built-in' way to determine the length inside the function. However you pass arr, sizeof(arr) will always return the pointer size. So the best way is to pass the number of elements as a seperate argument. Alternatively you could have a special value like 0 or -1 that indicates the end (like it is \0 in strings, which are just char []).
But then of course the 'logical' array size was sizeof(arr)/sizeof(int) - 1
Don't use a function, use a macro for this:
//Adapted from K&R, p.135 of edition 2.
#define arrayLength(array) (sizeof((array))/sizeof((array)[0]))
int main(void)
{
int ar[]={1,2,3};
printf("%d\n", arrayLength(ar));
return 0;
}
You still cannot use this macro inside a function like your temp where the array is passed as a parameter for the reasons others have mentioned.
Alternative if you want to pass one data type around is to define a type that has both an array and capacity:
typedef struct
{
int *values;
int capacity;
} intArray;
void temp(intArray array)
{
printf("%d\n", array.capacity);
}
int main(void)
{
int ar[]= {1, 2, 3};
intArray arr;
arr.values = ar;
arr.capacity = arrayLength(ar);
temp(arr);
return 0;
}
This takes longer to set up, but is useful if you find your self passing it around many many functions.
As others have said the obvious solution is to pass the length of array as parameter, also you can store this value at the begin of array
#include <stdio.h>
void temp(int *ar)
{
printf("%d\n", ar[-1]);
}
int main(void)
{
int ar[]= {0, 1, 2, 3};
ar[0] = sizeof(ar) / sizeof(ar[0]) - 1;
printf("%d\n", ar[0]);
temp(ar + 1);
return 0;
}
When you write size(ar) then you're passing a pointer and not an array.
The size of a pointer and an int is 4 or 8 - depending on ABI (Or, as #H2CO3 mentioned - something completely different), so you're getting sizeof(int *)/sizeof int (4/4=1 for 32-bit machines and 8/4=2 for 64-bit machines), which is 1 or 2 (Or.. something different).
Remember, in C when pass an array as an argument to a function, you're passing a pointer to an array.If you want to pass the size of the array, you should pass it as a separated argument.
I don't think you could do this using a function. It will always return length of the pointer rather than the length of the whole array.
You need to wrap the array up into a struct:
#include<stdio.h>
struct foo {int arr[5];};
struct bar {double arr[10];};
void temp(struct foo f, struct bar g)
{
printf("%d\n",(sizeof f.arr)/(sizeof f.arr[0]));
printf("%d\n",(sizeof g.arr)/(sizeof g.arr[0]));
}
void main(void)
{
struct foo tmp1 = {{1,2,3,4,5}};
struct bar tmp2;
temp(tmp1,tmp2);
return;
}
Inside the function ar is a pointer so the sizeof operator will return the length of a pointer. The only way to compute it is to make ar global and or change its name. The easiest way to determine the length is size(array_name)/(size_of(int). The other thing you can do is pass this computation into the function.
void Manager::byteArrayToDoubleArray(byte ch[]) {
int counter = 0;
// temp array to break the byte array into size of 8 and read it
byte temp[64];
// double result values
double res[8];
int index = 0;
int size = (sizeof(ch) / sizeof(*ch));
for (int i = 0; i < size; i++) {
counter++;
temp[i] = ch[i];
if (counter % 8 == 0) {
res[index] = *reinterpret_cast<double * const>(temp);
index++;
counter = 0;
}
}
}
Here result would be a list of double values with count = 8.
Your problem is two things. You have some typos and misunderstanding. And the C++ standard is somewhat broken in this area.
I'll try to fix both.
First, a helper function called laundry_pods. It takes raw memory and "launders" it into an array of a type of your choice, so long as you pick a pod type:
template<class T, std::size_t N>
T* laundry_pods( void* ptr ) {
static_assert( std::is_pod<std::remove_cv_t<T>>{} );
char optimized_away[sizeof(T)*N];
std::memcpy( optimized_away, ptr , sizeof(T)*N );
T* r = ::new( ptr ) T[N];
assert( r == ptr );
std::memcpy( r, optimized_away, sizeof(T)*N );
return r;
}
now simply do
void Manager::byteArrayToDoubleArray(byte ch[]) {
double* pdouble = laundry_pods<double, 8>(ch);
}
and pdouble is a pointer to memory of ch interpreted as an array of 8 doubles. (It is not a copy of it, it interprets those bytes in-place).
While laundry_pods appears to copy the bytes around, both g++ and clang optimize it down into a binary noop. The seeming copying of bytes around is a way to get around aliasing restrictions and object lifetime rules in the C++ standard.
It relies on arrays of pod not having extra bookkeeping overhead (which C++ implementations are free to do; none do that I know of. That is what the non-static assert double-checks), but it returns a pointer to a real honest to goodness array of double. If you want to avoid that assumption, you could instead create each doulbe as a separate object. However, then they aren't an array, and pointer arithmetic over non-arrays is fraught as far as the standard is concerned.
The use of the term "launder" has to do with getting around aliasing and object lifetime requirements. The function does nothing at runtime, but in the C++ abstract machine it takes the memory and converts it into binary identical memory that is now a bunch of doubles.
The trick of doing this kind of "conversion" is to always cast the double* to a char* (or unsigned char or std::byte). Never the other way round.
You should be able to do something like this:
void byteArrayToDoubleArray(byte* in, std::size_t n, double* out)
{
for(auto out_bytes = (byte*) out; n--;)
*out_bytes++ = *in++;
}
// ...
byte ch[64];
// .. fill ch with double data somehow
double res[8];
byteArrayToDoubleArray(ch, 64, res);
Assuming that type byte is an alias of char or unsigned char or std::byte.
I am not completly sure what you are trying to achieve here because of the code (sizeof(ch) / sizeof(*ch)) which does not make sense for an array of undefined size.
If you have a byte-Array (POD data type; something like a typedef char byte;) then this most simple solution would be a reinterpret_cast:
double *result = reinterpret_cast<double*>(ch);
This allows you to use result[0]..result[7] as long as ch[] is valid and contains at least 64 bytes. Be aware that this construct does not generate code. It tells the compiler that result[0] corresponds to ch[0..7] and so on. An access to result[] will result in an access to ch[].
But you have to know the number of elements in ch[] to calculate the number of valid double elements in result.
If you need a copy (because - for example - the ch[] is a temporary array) you could use
std::vector<double> result(reinterpret_cast<double*>(ch), reinterpret_cast<double*>(ch) + itemsInCh * sizeof(*ch) / sizeof(double));
So if ch[] is an array with 64 items and a byte is really an 8-bit value, then
std::vector<double> result(reinterpret_cast<double*>(ch), reinterpet_cast<double*>(ch) + 8);
will provide a std::vector containing 8 double values.
There is another possible method using a union:
union ByteToDouble
{
byte b[64];
double d[8];
} byteToDouble;
the 8 double values will occupie the same memory as the 64 byte values. So you can write the byte values to byteToDouble.b[] and read the resultingdouble values from byteToDouble.d[].
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)));
I am looking at a code dump from IDA pro. There is a function which as this layout:
garbled_name(int this...
unsigned int v5 ;
v5 = *(_Byte *)(this + 4);
...
What I am really curious about is what exactly the '+ 4' is doing? Is this an addition or something else?
Thanks
The code takes the integer 'this', adds 4 to it, casts it to a pointer to a byte, and then sets 'v5' to the value of the byte at that address.
It's just a member function of a C++ class, this being pointer to the object. This signature of the object is probably:
class some_class {
int i; // int, void*, short, anything with sizeof() <= 4, and it's not char.
// It also can be absent if it's a virtual class (AFAIK it's compiler dependend)
unsigned char c; // or c[N]
...
};
The code in question is:
some_class::some_fn(...){
unsigned int v5 = c; // or c[0]
...
};
It is a reference to the fifth byte from the beginning of the object. Depending on what compiler generated that code, it is most likely the item in class order which is at the fifth byte in the object instance.
EDIT: Sigh, I missed the "IDA Pro" part. I'll just leave this here for entertainment value, in case someone is wondering what "this+4" does in normal C++ code.
"this+4" takes your current this pointer, moves forward four times its size. Then it casts that to a byte pointer and reads it.
Consider this:
struct A {
void foo();
int x;
int y;
};
sizeof(A), on a 32-bit system, is most likely 8 bytes.
A myArray[8];
A *pA = myArray;
Now pA points to &myArray[0].
pA++;
Now pA points to &myArray[1], i.e. it moved 8 bytes forward.
void A::foo() {
A *pA = this + 4;
}
If you call this on &myArray[0], it will point to &myArray[4], i.e. 32 bytes further down the road.
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).