简体   繁体   中英

How to cast a void* to int in 64-bit platforms, using C?

I am a linguist in charge of a C program, so please excuse me if the answer is obvious. I have the following code:

typedef struct array_s {
  (...)
  void **value;
} array_t;
typedef array_t *array_pt;

array_pt array_new (int size) {
  (...)
  array->value = (void **)malloc(size*sizeof(void *));
}

void* array_get (array_pt arr, int i) {
  return arr->value[i];
}

int main () {
  int a = 1234;
  int *ptr = &a;

  array_pt array = array_new(1);
  array_add(array, ptr);

  printf("%i\n", (int)array_get(array, 0));
}

It is supposed to provide me with a multi-purpose array (for storing int and char* , if I understood I can only use void ), and I guess there are no problems of allocating/freeing. However, I cannot get to cast it into anything useful (ie, get back the "original" int/char*), and for what I understood it could be because I am in a 64-bit system and the size of a pointer to void is different from the size of a pointer to int / char* (the program is supposed to be used in both 64 and 32 bit systems). I tried using intptr_t and other alternatives, to no luck.

How can I be sure that the code will accept any data type and work on both 32 and 64 bit systems? Thank you.

EDIT:

Sorry for not adding array_add , here it is:

unsigned int array_add (array_pt array, void *ptr) {
  (...) // get the next index
  // allocate if needed
  array->value = (void **)realloc(array->value, array->size*sizeof(void *));

  array->value[index] = p;
}

You need to dereference your pointer:

int* temp = array_get(array, 0);
printf("%i\n", *temp);

However, I strongly recommend avoiding this type of approach. You're basically giving away the small amount of help the compiler in C will normally provide - purposefully trying to make non-typesafe arrays.

You need to decide what is it you are trying to do in this case.

(1) If you want to use your void * array to store int values ( actual int forcefully converted to void * ), then you should add these int values to the array as follows

int a = 1234; 

array_pt array = array_new(1); 
array_add(array, (void *) a); 

and then get them back from array as follows

int a = (int) array_get(array, 0); 
printf ("%d\n", a);

or simply

printf ("%d\n", (int) array_get(array, 0)));

That last part is exactly what you did, but you got the first part wrong.

This is a cast-based approach, which is ugly in many ways, but it has certain practical value, and it will work assuming void * is large enough to hold an int . This is the approach that might depend on the properties of 32- and 64-bit systems.

(2) If you want to use your void * array to store int * values (pointers to int ), then you should add these int values to the array as follows

int a = 1234; 

array_pt array = array_new(1); 
array_add(array, &a); 

and then get them back from array as follows

int *pa = array_get(array, 0); 
printf ("%d\n", *pa);

or simply

printf ("%d\n", *(int *) array_get(array, 0));

This approach is perfectly safe from any portability problems. It has no 32- or 64-bit issues. A void * pointer is guaranteed to safely hold a int * pointer or any other data pointer.

If that was your intent, then you got the first part right and the last part wrong.

Either this or that. You code appears to be a strange mix of the two, which is why it doesn't work, and which is why it is impossible to figure out from your original message which approach you were trying to use.

intmax_t should be an integer type that is 32 bits on 32bits compilers and 64bits on 64bit compilers. You could use %j in your printf statement to print intmax_t. The size of pointers on one system is always the same - independently of them pointing to int, char or void.

printf("%j\n", (intmax_t)array_get(array, 0));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM