What does it mean to convert an integer value to a void*
or viceversa from a memory point of view?
My understanding is void*
is an address to a blo
It is useful to be able to cast a pointer to integer type for pointer arithmetic. For instance, the offsetof()
macro, which calculates the offset of a member within a structure, needs this kind of conversion.
However, it must be ensured that the primitive type used for this is able to handle a pointer: here, for 64 Linux for instance, when using gcc, this is not the case: void *
has size 8, an int has size 4.
The offsetof
macro is defined as such:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
It is used prominently in the Linux kernel's doubly linked list implementation, very simply defined as:
struct list_head { struct list_head *prev, *next; }
This struct is embedded within kernel structures, as in:
struct something {
//...
struct list_head list;
//...
}
When walking a list, the code needs to grab a pointer to the encoding structure. This is done as this (simplified definition):
#define container_of(ptr, type, member) \
(type *)((char *)ptr - offsetoff(type, member))
#define list_entry(list, type, member) \
container_of(list, type, member)
And in the code, you will very often see:
struct something *s;
list_for_each(listptr, somehead) {
s = list_entry(listptr, struct something, list);
//...
}
which would simply not be doable without this kind of macro and pointer arithmetic. But it is very dependent on the toolchain.
It would be like comparing apples with oranges if any attempt was being made to make any comparison. But there isn't. Basically, in the majority of architectures out there, an int can be casted to a void pointer without the loss of any information, and a void pointer can also be casted back to an int, again without the loss of any information. Of course, you should not try dereferencing that pointer, because it does not point to any meaningful memory location: it is just a variable containing the same bit-pattern as the bit pattern that the integer used to contain before the cast.
This is quite like comparing apples and oranges. The only way that this code works is because you are explicitly casting it back and forth.
The C compiler is just copying the bytes from the int into the space for the pointer and back, just like how you can hold a char in an int.
This could even cause your number to be messed up if for some reason an 'int' is longer than a 'void *' on your platform.
If you actually do want have a number to convert from integers into pointers and back, look into intptr_t
. That type is actually designed to store both integers and pointers.
Both void*
pointer (or any pointer for that matter) and int
are, roughly speaking, numbers. They may be of different bitsize, but it is unlikely that pointer is smaller than int
, so that makes the operation reversible. Of course, it's illegal and you should never dereference the pointer that has no valid location to point to.
The C standard specifies that it must be possible to convert a void pointer to an integral type such that converting the integral type back to a void pointer will yield the same pointer. I'm not sure if it requires that converting a null pointer to an integer yield the value zero, or if only numeric literal zeroes are recognized as special. On many implementations, the integer value represents a hardware address, but the standard makes no such guarantee. It would be entirely possible that on hardware which included a special trap for hardware address 0x12345678, converting a pointer to an integer would subtract 0x12345678 from the hardware address, and converting an integer to a pointer would add 0x12345678 back in (thus an integer value of zero would represent a null pointer).
In many cases, particularly when developing for embedded controllers, the compiler vendor will explicitly specify what hardware address will be accessed when converting a particular integer value to a pointer type. On processors with a single linear address space, converting an integer value 0x12345678 to a pointer would generally yield a pointer which refers to address 0x12345678; the hardware reference manual would indicate if there was anything special about that location. On processors with more 'interesting' address spaces, it may be necessary to use something other than the hardware address as the pointer. For example, on antique IBM PC computers, the display buffer was mapped at hardware address 0xB8000, but in most compilers, the address would be expressed as (short far*)0xB8000000.
Casting int
to void *
is rather meaningless and should not be done as you would be attempting to cast a non-pointer to a pointer. Quoting the C99 standard, section 6.3.2.3 item 5:
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
You could cast int *
to void *
(any pointer is convertible to void *
which you can think of like the "base type" of all pointers).
Casting void *
to int
is not portable and may be completely wrong depending on the platform you use (e.g. void *
maybe 64 bits wide and int
may only be 32 bits). Quoting the C99 standard again, section 6.3.2.3 item 6:
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
To solve this, some platforms provide uintptr_t
which allows you to treat a pointer as a numeric value of the proper width.