Reputation: 1299
I have a function in C that needs to receive a pointer to an array (with an unspecified type).
To do so, I use void**, as I would use void* to receive an array of unspecified elements.
There's a problem unfortunately: the compiler gives a warning (passing argument 1 of 'f' from incompatible pointer type). If I ignore the warning, and try to execute the program, everything works as expected.
The only way to get rid of the warning is to cast whatever I try to pass to the function to void**.
Why does C behaves like that? And is there a better way to solve the warning?
PS: I need to compile using GCC with the flags -std=gnu89 -pedantic -Wall
Example
int f(void** param){ return 1; }
int main(){
int *arr = malloc(sizeof(int) * 20);
int i;
for(i=0; i < 20; i++) arr[i] = i;
f(&arr);
}
Upvotes: 3
Views: 355
Reputation: 41017
It seems that you want to modify the address of the data (not the value) inside the function, you can't do that directly with a void *
because you can't use arithmetic with void *
, but you can pass the size of the first element and a chunk of bytes (char *
), suppose you want to change the address of arr
to arr + 1
(the second element of the array) inside the function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f(void *ptr, size_t size)
{
// char *p = *ptr; Wrong, you can't dereference a void * without a cast
char *p = *(char **)ptr; /* pointer to address of ptr */
memmove(p, p + size, size); /* assign the address of ptr + 1 to ptr */
}
int main(void)
{
int *arr = malloc(sizeof(int) * 20);
int i;
for (i = 0; i < 20; i++) arr[i] = i;
f(&arr, sizeof arr[0]);
printf("%d\n", arr[0]);
return 0;
}
Output:
1
Upvotes: 2
Reputation: 16107
Although void *
is the "generic pointer" in C, void **
isn't a "generic pointer to pointer". Instead, it's nothing more than the "specific pointer to void *
, the generic pointer".
In your case, a int **
is converted implicitly to a void **
, which is not generic. Since a void **
is not guaranteed to be able to hold all pointer variables (thus incompatible to a int **
), the compiler raises a warning.
Here is the warning generated by clang:
main.c:7:7: warning: incompatible pointer types passing 'int **' to parameter of
type 'void **' [-Wincompatible-pointer-types]
f(&arr);
^~~~
main.c:1:14: note: passing argument to parameter 'param' here
int f(void** param){ return 1; }
To eliminate this warning, you can have int f(void* param);
, and cast param
to int **
inside the function. There will be no warning because a void *
can be used to store any pointer (Quoted from N1570):
6.3.2.3 Pointers
1 A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
Upvotes: 2
Reputation: 1153
The pointer to anything type is void*
, and the compiler will not complain about conversions to that type. But void**
is not a pointer to anything, it's a pointer to an array of pointers to anything, which is quite different from a pointer to an array of pointers to integers, so the compiler complains.
So, to solve the warning, yes you would need to cast explicitly.
Upvotes: 4