I have a function which creates an array of pointers. The function which allocates the memory returns the new memory pointer through a parameter passed to the function. The simplest code which can reproduce the problem is as follows:
void foo (void** new_mem, size_t bytes)
{
*new_mem = malloc(bytes);
}
int main (void)
{
int** ptr_arr; // Want to create an array of pointers
foo(&ptr_arr, sizeof(int*)*100); // Create an array size of 100
// compiler emits warning:
// 'void **' differs in levels of indirection from 'int ***'
return 0;
}
I could cast the first parameter passed to foo like so: '(void**)&ptr_arr' to get rid of the warning, however, I'm wondering: Is there a more appropriate solution?
Although there's a guaranteed conversion from int * to void *, there's no such guarantee for converting from int ** to void **. To think about why this might be, consider that an int * might actually be smaller than a void *. As a result, using a void ** pointer to walk over an array of int *s will walk the wrong stride and get the wrong data. Furthermore, there's no guarantee that int * will use the same representation as void *, only that there is a way to convert between them.
In practice, I don't know of any machines where this will fail. But it's not guaranteed by the standard.
EDIT: eek, and what everyone says about passing an int ***. But even if you pass an int **, the above still applies.
EDIT2: the comp.lang.c FAQ has an excellent discussion about this.
The problem is you're taking the address of a double pointer and passing it to a double pointer parameter. Taking the address of a value creates a pointer so you end up really with a triple pointer int*** which is why you get the error.
Casting the result to void** will technically work here although it is bordering on an abuse on the type system.
The trouble is ptr_arr is already an int **,
when you do an &ptr_arr, it will show as int *** , so what you are doing is incorrect.
So, you can just pass ptr_arr if your intention is to pass an int **
Also, I feel your code can do well with a cleanup. Your approach seems to be wrong.
Related
Very simply, is the following code safe/portable?
#include <stdio.h>
#include <stdlib.h>
int add(int *a, int *b)
{
return *a + *b;
}
int main()
{
int x = 2;
int y = 3;
void *ptr1 = &x;
void *ptr2 = &y;
fprintf(stdout, "%d + %d = %d\n", x, y, add(ptr1, ptr2));
return EXIT_SUCCESS;
}
I've compiled this with -Wall -Werror and -Wextra and received no warnings; it seems to run fine.
There's two things to consider:
C allows the implicit conversion from a void pointer to any other object pointer type. So it's syntactically okay to pass those arguments.
The type of the actual object being pointed to, and the type of the pointer the function expects, must satisfy strict aliasing constraints, otherwise your program is in undefined behavior land.
You are okay on both points. So your program is perfectly fine.
It is safe:
C99
A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
But you need to make sure your original pointer type is correct.
It's fine but by the skin of your teeth.
You are converting an int* to void* and that is converted back to int* as the pointer is passed by value into add.
If, for example, add took two pointers to double, say, then the behaviour of your code would be undefined.
It's "safe" in that the behavior is well defined. Having a function declared as accepting void * is normal when it needs to deal with many different types of data; e.g. memcpy.
It's not morally safe. By passing void * you are making the compiler unable to check that the pointer you are passing points to memory that holds data in the form and quantity that you expect. It is then up to you to enforce this.
In your trivial example you can see that the objects are actually int, and everything is fine.
In general, however, where we pass void * to a function, we should also pass additional information describing the memory we are handing over in enough detail that the function can do its job; if we have a function that only ever deals with one type, we look long and hard at the design decisions that made us pass around void * values instead of that type.
For sanity's sake (and, depending on the compiler, performance), please consider also marking arguments you are not writing to as const.
If you know that the pointers that you cast to void * are always to a known set of types (e.g. char, short, int, etc.), you can create a struct type consisting of a union together with a discriminant, and pass that instead, re-casting if necessary.
You can pass it as a pointer to an undefined type, just to be a bit more specific than void *, and in that way some responsibility is taken.
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.
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);
I found this function definition
void *func(void *param) {
}
Actually, I have a certain confusion regarding this function definition. What does void * mean in the return type of the function as well as the argument. I am a beginner in C. So please don't mind. Thank you
void *func(void *param) {
int s = (int)param;
....
}
Well looking at the above program which I found. I think it should have been
int *s = (int *)param;
isn't it? I am confused
void * means it's a pointer of no specific type, think of it as a generic pointer, unlike say int * an int pointer.
You can cast it into a different type if need be (for instance if you are going to do pointer arithmetic with the pointer).
You might find this SO question of use: Concept of void pointer in C programming
It simply means that the function func takes one parameter which is a pointer (to anything) and returns a pointer (to anything). When you use a void *, you are telling the compiler "this is a pointer, but it doesn't matter at this point what it's a pointer to".
When you want to actually use the data it's pointing to, you need to cast it to a pointer to some other type. For example, if it points to an int, you can create an int * variable and dereference that:
int *int_ptr = (int *)param;
// now (*int_ptr) is the value param is pointing to
you can think of it as a raw pointer, nothing more than an address, think about it, pointers are nothing more than address right, so they should all be of equal size, either 32 or 64 bits in most modern systems but if thats the case why do we say int * or char * or so on if they are all the same size, well thats because we need of a way to interpret the type we are pointing to, int * means when we dereference go to that address and interpret the 4 bytes as an int or char * means when we dereference go to that address and get a byte, so what happens when you dereference a void * well you get warning: dereferencing ‘void *’ pointer basically we really can't and if you do its affects are compiler dependent, the same applies when we do arithmetics on it.
So why bother using them? well I personally don't and some groups dont particularly like them, fundamentally they allow you to create fairly generic subroutines, a good example would be memset which sets a block of memory to a certain byte value, its first argument is a void * so it won't complain whether giving a char * or int * due note that it works on a per byte basis, and you need to properly calculate the total size of the array.
void *func(void *param) {
}
param is a void pointer means it is a pointer of any reference type. since a void pointer has no object type,it cannot be dereferenced unless it is case.
so void *param;
int *s=(int*)param;
here since param is an pointer variable so you will have to cast it as a pointer variable.not to a int type as you did there.
e.g.
int x;
float r;
void *p=&x;
int main()
{
*(int *)p=2;
p=&r;
*(float*)p=1.1;
}
in this example p is a void pointer. now in main method I have cast the p as a int pointer and then as a float pointer so that it can reference to first a integer and then a float.
Returning a pointer of any type. It can be of any datatype.
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.