Is it legal to access a pointer type through a void **?
I've looked over the standards quotes on pointer aliasing but I'm still unsure on whether this is legal C or not:
int *array;
void **vp = (void**)&array;
*vp = malloc(sizeof(int)*10);
Trivial example, but it applies to a more complex situation I'm seeing.
It seems that it wouldn't be legal since I'm accessing an int * through a variable whose type is not int * or char *. I can't come to a simple conclusion on this.
Related:
Does C have a generic "pointer to a pointer" type?
C-FAQ question 4.9
No. void ** has a specific type (pointer to a pointer-to-void). I.e. the underlying type of the pointer is "pointer-to-void"
You're not storing a like-pointer value when storing a pointer-to-int. That a cast is required is a strong indicator what you're doing is not defined behavior by the standard (and it isn't). Interestingly enough, however, you can use a regular void* coming and going and it will exhibit defined behavior. In other words, this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *array;
void *vp = &array;
int **parray = vp;
*parray = malloc(sizeof(int)*10);
}
is legitimate. Your original example won't even compile if I remove the cast and use apple llvm 4.2 (clang), due precisely to incompatible pointer types, i.e. the very subject of your question. The specific error is:
"Incompatible pointer types initializing 'void **' with an expression of type 'int **'"
and rightfully so.
Pointer to different types can have different sizes.
You can store a pointer to any type into a void * and then you can recover it back but this means simply that a void * must be large enough to hold all other pointers.
Treating a variable that is holding an int * like it's indeed a void * is instead, in general, not permitted.
Note also that doing a cast (e.g. casting to int * the result of malloc) is something completely different from treating an area of memory containing an int * like it's containing a void *. In the first case the compiler is informed of the conversion if needed, in the second instead you're providing false information to the compiler.
On X86 however they're normally the same size and you're safe if you just play with pointers to data (pointers to functions could be different, though).
About aliasing any write operation done through a void * or a char * can mutate any object so the compiler must consider aliasing as possible.
Here however in your example you're writing through a void ** (a different thing) and the compiler is free to ignore potentially aliasing effects to int *.
Your code may work on some platforms, but it is not portable. The reason is that C doesn't have a generic pointer to pointer type. In the case of void * the standard explicitly permits conversions between it and other pointer to complete/incomplete types, but this is not the case with void **. What this means is that in your code, the compiler has no way of knowing if the value of *vp was converted from any type other than void *, and therefore can not perform any conversions except the one you explicitly cast yourself.
Consider this code:
void dont_do_this(struct a_t **a, struct b_t **b)
{
void **x = (void **) a;
*x = *b;
}
The compiler will not complain about the implicit cast from b_t * to void * in the *x = *b line, even though that line is trying to put a pointer to a b_t in a place where only pointers to a_t should be put. The mistake is in fact in the previous line, which is converting "a pointer to a place where pointers to a_t can be put" to "a pointer to a place where pointers to anything can be put". This is the reason there is no implicit cast possible. For an analogous example with pointers to arithmetic types, see the C FAQ.
Your cast, then, even though it shuts the compiler warning up, is dangerous because not all pointer types may have the same internal representation/size (e.g. void ** and int *). To make your code work in all cases, you have to use an intermediate void *:
int *array;
void *varray = array;
void **vp = &varray;
*vp = malloc(sizeof(int) * 10);
Related
Why are void pointers necessary, as long as one could cast any pointer type to any pointer type, i.e.:
char b = 5;
int*a = (int*)&b;//both upcasting
or
int b = 10;
char*a = (char*)b;//and downcasting are allowed
?
Also, why there is no need for cast when using malloc/calloc/realloc ?
one could cast any pointer type to any pointer type
Not quite. void * is defined to convert any object pointer1 to void * and back again with an equivalent value. It does not need any cast.
In less common architectures, the size and range of some other pointers may be smaller than void *. Casting between other pointers type may lose necessary information.
void * provides a universal object pointer type.
void *p = any_object_pointer; // No casts required
any_object_pointer = p; // No casts required
char * could substitute for void *, except conversion to and from other object pointers requires casts.
OP's char b = 5; int*a = (int*)&b; risks undefined behavior as the alignment needs of int * may exceed char *.
1 Function pointers may be wider than void*. void * and other pointers are object pointers. C lacks a truly universal pointer type.
void pointers are really useful to create a generic API. You might think of qsort function which can be used to sort arrays of any types. void pointers can be used if the API does not know the concrete type of the pointer.
void qsort(
void *base,
size_t number,
size_t width,
int (__cdecl *compare )(const void *, const void *)
);
Regarding allocation functions, it's the same thing. The C runtime does not know the type of the effective object. But this is not a problem as user can use generic pointer void.
So void pointers are considered as generic pointers, very useful for polymorphism, that's why the C language makes casting to void optional.
"Why are void pointers necessary, as long as one could cast any pointer type".
The alloc function would then have to use common denominator such as char. But then it would be confusing to have to cast to whatever we really need. "void" just means "a bunch of bytes".
I have similar "generic" procedure like qsort, which has a void pointer (pointing at an array) and also a function pointer parameter. This function should work on any type of array.
Example:
void do_something(void * array, int count, int size, void (*test)(const void*)){
int i;
for(i=0; i<count; i++){
test(array + (index * size));
}
}
This however gives me the following warning (gcc test.c -pedantic-errors):
error: pointer of type ‘void *’ used in arithmetic [-Wpedantic]
And after some research I found out it's a bad practice to use void pointers like this. (E.g. Pointer arithmetic for void pointer in C)
So how does the standard library do this kind of stuff for like qsort? Looking at this code: (http://aturing.umcs.maine.edu/~sudarshan.chawathe/200801/capstone/n/qsort.c), I see the following:
void
_quicksort (void *const pbase, size_t total_elems, size_t size,
__compar_fn_t cmp)
{
register char *base_ptr = (char *) pbase;
....
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
...
}
Are they casting to (char *) regardless of the actual type?
i asked similar question Can I do arithmetic on void * pointers in C?.
Void * arithmetic is not defined. What does it mean to add 1 to a void pointer ? Most compilers (if they allow it) treat it as incrementing by sizeof(char) ("the next byte") but warn you.
So the right thing to do is to explicitly make it do what you want -> cast to char* and increment that
Pointer arithmetic on incomplete data type void is not legal and that is what the compiler is complaining.
As you can see in the _quicksort() the pointer is a constant one so that you can't modify the address the pointer is pointing to. There is no arthmetic operation happening on the void pointer.
Making a pointer void just takes away the "context" of the pointer - That is, how the system should look at the pointer or whatever the pointer is holding.
For this reason, compilers do not do arithmetic on void pointers. In order to do pointer arithmetic, the compiler needs to know the type of the pointer such that it can do the proper conversions (if the pointer holds an int, it will not do an addition of with 32 bits or at least it will let you know something is gone awry!).
For this reason, the only way to do this is to cast the pointer to something and do it - I would not recommend it unless you know very well what the pointer is getting. Void pointers are rather very dark programming.
I have a situation where in the address inside the void pointer to be copied to a another pointer. Doing this without a type cast gives no warnings or errors. The pseudo code looks like
structA A;
void * p = &A;
structA * B = p;// Would like to conform this step
I don't foresee any problems with this.
But since this operation is used over a lot of places, I would like to conform whether it can have any replications. Also is there any compiler dependency?
No, this is fine and 100% standard.
A void * can be converted to and from any other data/object pointer without problems.
Note that data/object restriction: function pointers do not convert to/from void *.
This is the reason why you shouldn't cast the return value of malloc(), which returns a void *.
In C a void * is implicitly compatible with any pointer. That why you don't need to cast when e.g. passing pointers of any type to functions taking void * arguments, or when assigning to pointer (still of any type) from function returning void * (here malloc is a good example).
I've seen a lot of the following in older C code:
type_t *x = (type_t *) malloc(...);
What's the point of casting the pointer returned from malloc() since it's void *? Is it because older C compilers didn't support void pointers and malloc() used to return char * instead?
Your own explanation is the right one. Pre-ANSI C ('K&R' C) did not have a void * type with implicit conversion. char * doubled as a pseudo void * type, but you needed the explicit conversion of a type cast.
In modern C the casting is frowned upon because it can suppress compiler warnings for a missing prototype of malloc. In C++, the casting is needed (but there you should be using new instead of malloc most of the time).
Update
My comments below that try to explain why the cast is required were a bit unclear, I'll try to explain it better here. You might think that even when malloc returns char *, the cast is not needed because it is similar to:
int *a;
char *b = a;
But in this example a cast is also needed. The second line is a constraint violation for the simple assignment operator (C99 6.5.1.6.1). Both pointer operands need to be of compatible type. When you change this to:
int *a;
char *b = (char *) a;
the constraint violation disappears (both operands now have type char *) and the result is well-defined (for converting to a char pointer). In the 'reverse situation':
char *c;
int *d = (int *) c;
the same argument hold for the cast, but when int * has stricter alignment requirements than char *, the result is implementation defined.
Conclusion: In the pre-ANSI days the type cast was necessary because malloc returned char * and not casting results is a constraint violation for the '=' operator.
The problem here is not compatibility with any dialect of C. The problem is C++. In C++, a void pointer cannot be automatically converted to any other pointer type. So, without an explicit cast, this code would not compile with a C++ compiler.
I'm not aware that malloc ever returned a char*.
But implicit casting from void* to type_t* (or any other type) hasn't always been allowed.
Hence, the need to explicitly cast to the proper type.
What's the point of casting the pointer returned from malloc() since it's void *?
Quite the contrary. You need to cast a void pointer to an actual type before you can use it, because a void * signifies nothing about the data stored at that location.
I have seen a function whose prototype is:
int myfunc(void** ppt)
This function is called in a C file as
a = myfunc(mystruct **var1);
where mystruct is typedef for one of structure we have.
This works without any compilation errors in MSVC6.0, But when I compile it with some other C compiler, it gives an error at the place where this function is called with error message:
Argument of type mystruct ** is incompatible with parameter of type void **
The argument of myfunc() is kept as void** because it seems to be a generic malloc kind of function to be called with various structure variable types for memory allocation
Is there any type such as void ** allowed in C standard/any C compilers?
How do I fix this? [I tried casting the function call argument to mystruct**, but it didn't work]
-AD
The comp.lang.c FAQ addresses this issue in detail in Question 4.9. In short, they say it's not strictly portable to cast an arbitrary pointer-to-pointer to a void **; they go on to explain that "code like this may work and is sometimes recommended, but it relies on all pointer types having the same internal representation (which is common, but not universal)." They go on to explain that "any void ** value you play with must be the address of an actual void * value somewhere; casts like (void **)&dp, though they may shut the compiler up, are nonportable (and may not even do what you want)."
So, you can safely/portably achieve the desired behavior with code like:
some_type *var1 = foo();
void *tmp_void_ptr = (void *)var1;
myfunc(&tmp_void_ptr);
void** is valid but, based on your error message, you probably have to explicitly cast the argument as follows:
mystruct **var1;
x = myfunc ((void**) var1);
That's because the myfunc function is expecting the void** type. While void* can be implicitly cast to any other pointer, that is not so for the double pointer - you need to explicitly cast it.
There is a reason the compiler cannot automatically cast from mystruct** to void**.
Consider the following code:
void stupid(struct mystruct **a, struct myotherstruct **b)
{
void **x = (void **)a;
*x = *b;
}
The compiler will not complain about the implicit cast from myotherstruct* to void* in the *x = *b line, even though that line is trying to put a pointer to a myotherstruct in a place where only pointers to mystruct should be put.
The mistake is in fact in the previous line, which is converting "a pointer to a place where pointers to mystruct can be put" to "a pointer to a place where pointers to anything can be put". This is the reason there is no implicit cast. Of course, when you use a explicit cast, the compiler assumes you know what you are doing.
This question is slightly confusing. But yes, void ** is certainly legal and valid C, and means "pointer to pointer to void" as expected.
I'm not sure about your example of a call, the arguments ("mystruct **var1") don't make sense. If var1 is of type mystruct **, the call should just read a = func(var1);, this might be a typo.
Casting should work, but you need to cast to void **, since that is what the function expects.
As dirty as it may look like: sometimes you can't solve a problem without using void **.
Yes, void ** is perfectly acceptable and quite useful in certain circumstances. Also consider that given the declaration void **foo and void *bar, the compiler will know the size of the object pointed to by foo (it points to a pointer, and all pointers are the same size except on a few ancient platforms you needn't worry about), but it will not know the size of the object pointed to by bar (it could point to an object of any size). You can therefore safely perform pointer arithmetic on void ** pointers but not on void * pointers. You must cast them to something else first, like a char *. GCC will allow you to pretend that void * and char * are equivalent, each pointing to an object a single byte in size, but this is nonstandard and nonportable.