我想传递一个指向函数的“多态”数组。
我可以在没有警告的情况下执行以下操作:
foo (void* ptr);
bar()
{
int* x;
...
foo(x);
}
gcc显然会自动将x
转换为(void*)
,这只是花花公子。
但是,当我执行以下操作时,我会收到警告:
foo (void** ptr);
bar()
{
int** x; // an array of pointers to int arrays
...
foo(x);
}
note: expected ‘void **’ but argument is of type ‘int **’
warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
我的问题是:为什么传递(int*)
作为(void*)
参数而不是“不兼容”,但(int**)
作为(void**)
参数是?
由于所有指针类型都是相同的大小(对吗?自从我使用C以来已经有一段时间了), 我仍然可以做类似的事情:
void mainFunc1(int** arr, int len)
{
//goal is to apply baz to every int array
foo(baz, arr, len);
}
void mainFunc2(double** arr, int len)
{
//goal is to apply baz to every int array
foo(qux, arr, len);
}
// I PROMISE that if I pass in a (int**) as ptr, then funcPtr will interpret its (void*) argument as an (int*)
void foo(funcPtr f, void** ptr, int len)
{
for(int i = 0; i < len; i++)
{
f(ptr[i]);
}
}
void baz(void* x)
{
int* y = (int*)x;
...
}
void qux(void* x)
{
double* y = (double*)x;
...
}
所有void指针的目的是使我可以使用一个函数指针,该函数指针应用于(在堆栈中)具有不同类型的ptr参数的函数:一些将采用int
数组,一些将采用double
数组{1}}数组等
答案 0 :(得分:5)
注意:void*
是通用的。但void**
不是。您可以将任何类型的地址分配给void*
变量,但void**
只能分配void*
变量的地址。
void* generic;
int i;
int *ptri = &i;
generic = ptri;
或
char c;
int *ptrc = &c;
generic = ptrc;
有效,但以下是错误:
void** not_generic;
int i;
int *ptri = &i;
int **ptr_to_ptr1 = &ptri;
void** not_generic = ptr_to_ptr1;
错误:将int**
分配给void**
。
是的,你可以这样做:
void** not_generic;
not_generic = &generic;
对于通用数组函数,只需使用void* a
,如下所示:
enum {INT, CHAR, FLOAT};
void print_array(void* a, int length, int type){
int i = 0;
for(i = 0; i < length; i++){
switch(type){
case INT:
printf("%d", *((int*)a + i));
break;
case CHAR:
printf("%c", *((char*)a + i));
break;
case FLOAT:
printf("%f", *((float*)a + i));
break;
}
}
}
您最好使用宏编写此功能。
将此功能称为:
假设int
:
int a[] = {1, 2, 3, 4};
print_array(a, sizeof(a)/sizeof(a[0]), INT);
假设char
:
char a[] = {'1', '2', '3', '4'};
print_array(a, sizeof(a)/sizeof(a[0]), CHAR);
答案 1 :(得分:2)
因为C中没有通用的指向指针类型。
答案 2 :(得分:0)
简短的回答是:任何类似于
的东西<datatype>* <variable_name>
可以在参数声明的类型为void *的地方传递,因为void *是通用的。但是,void **不是。所以自动铸造失败了。