I've been doing some thinking. I haven't found anything directly answering this question, but I think I know the answer; I just want some input from some more experienced persons.
Knowns:
A void pointer points to just a memory address. It includes no type information.
An int pointer points to a memory address containing an int. It will read whatever is in the memory address pointed to as an integer, regardless of what was stuffed into the address originally.
Question:
If a void double pointer void ** foo
were to point to a dynamically allocated array of void pointers
void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);
is it true, as I am supposing, that because of the unique nature of void pointers actually lacking any sort of type information that instead of void ** foo
an equivalent statement would be
void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);
and that when I use indirection to access by assigning a specific type, such as with
(It was pointed out that I can't dereference void pointers. For clarity to the purpose of the question the next line is changed to be appropriate to that information)
int ** fubar = bar;
that I would get an appropriate pointer from the single void pointer which is just acting like a double pointer?
Or is this all just in my head?
It is permissible to assign the result of
malloc
to avoid *
object and then later assign it to anint **
object. This is because the return value ofmalloc
has typevoid *
anyway, and it is guaranteed to be suitable for assignment a pointer to any type of object with a fundamental alignment requirement.However, this code:
is not guaranteed by the C standard to work; it may have undefined behavior. The reason for this is not obvious. The C standard does not require different types of pointers to have the same size. A C implementation may set the size of an
int *
to one million bytes and the size of avoid *
to four bytes. In this case, the space allocated for 1000void *
would not be enough to hold oneint *
, so the assignment to*fubar
has undefined behavior. Generally, one would implement C in such a way only to prove a point. However, similar errors are possible on a smaller scale: There are C implementations in which pointers of different types have different sizes.A pointer to an object type may be converted to a pointer to another object type provided the pointer has alignment suitable for the destination type. If it does, then converting it back yields a pointer with the original value. Thus, you may convert pointers to
void *
to pointers tovoid
and back, and you may convert pointers tovoid *
to pointers toint *
and back, provided the alignments are suitable (which they will be if the pointers were returned bymalloc
and you are not using custom objects with extended alignments).In general, you cannot write using a pointer to an object type and then read the same bytes using a pointer to a different object type. This violates aliasing rules. An exception is that if one of the pointers is to a character type. Also, many C implementations do support such aliasing, but it may require setting command-line options to enable such support.
This prohibition on aliasing includes reinterpreting pointers. Consider this code:
In the fourth line,
c
points to the bytes thatb
occupies but*c
tries to interpret those bytes as avoid *
. This is not guaranteed to work, so the value thatd
gets is not necessarily a pointer toa
, even when it is converted toint *
as in the last line.