开发者

Cast 32 bit int to 64 void * pointer without warning

开发者 https://www.devze.com 2023-04-04 21:16 出处:网络
I have a \"generic\" linked link in C that takes void * data to store the data in a Node. insertNode(linkedList * list, void *data);开发者_如何学运维

I have a "generic" linked link in C that takes void * data to store the data in a Node.

insertNode(linkedList * list, void *data);开发者_如何学运维

//Storing/retrieving a string works fine;
char *str="test"; 
insertNode(list, str);
char *getback=(char *)node->data;

//Storing/retrieving an Int results a cast warning
int num=1;
insertNode(list,(void *)num);
int getback=(int)node->data;

This is because int is 32 bit, but void * is 64 bit on x64 machine. What is the best practice to get rid of this error?


Use intptr_t or uintptr_t. They are integers of the same size as a pointer:

#include <stdint.h>
...
intptr_t num = 1;
insertNode(list, (void *) num);
intptr_t getback = (intptr_t) node->data;

Of course, the maximum value that you can store depends on the system, but you can examine it at compile time via INTPTR_MIN and INTPTR_MAX.


Using a void * member to store an integer value isn't very good practice - apart from anything else, there's no guarantee what range of integers are storable in this way. If you want to store either a pointer or an integer in your structure, then what you should be using is a union:

union data {
    void *p;
    int i;
};

insertNode(linkedList * list, union data data);

// Storing/retrieving a string:
char *str="test"; 
union data d;
d.p = str;
insertNode(list, d);
char *getback = node->data.p;

// Storing/retrieving an int:
int num = 1;
union data d;
d.i = num;
insertNode(list, d);
int getback = node->data.i;

If you have a compiler that supports C99 constructs, you can make it a little neater by avoiding the local union variable:

// Insert a string
insertNode(list, (union data){ .p = str});

// Insert an int
insertNode(list, (union data){ .i = num});


You can cast it twice: insertNode( list, (void *)(uint64_t) num);

Or you can use "unsigned long" for num instead of int. At least in my experience, sizeof(unsigned long) == sizeof(void *) on both 32 and 64-bit systems. Using uintptr_t may be more correct; it's been a while since I've read the standards.


Are you sure you're doing what you actually want to be doing? In the first example with the string you are passing the pointer to the string literal to insertNode, while in the second example ((void *)num) you are casting the value of the int to a pointer to void. Did you actually want to do this: insertNode(list,(void *)&num);, i.e., passing the reference to the data like you were doing in the first example?

Also as an aside, char *str="test"; makes str point to a string literal, which is read-only. So you really should be doing const char *str="test";. If you wanted a normal (writable) string then char str[] = "test";.

Apologies if you already knew these things and actually wanted to store an int in a void *, I just can't imagine why you would.

Edit: If you actually want generic storage space then a union would be a safe approach. There is absolutely no guarantee that an int will fit in a void * in standard C, even though in most implementations it probably does.

0

精彩评论

暂无评论...
验证码 换一张
取 消