使用和解除引用(void **)
我想传递一个指向函数的“多态”数组。
我可以在没有警告的情况下做以下事情:
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
数组,等等。
注意: 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; } } }
您最好使用宏编写此函数。
将此function称为:
假设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);
因为C中没有通用的指向指针类型。
参考: C FAQ问题4.9
简短的回答是:任何类似的东西
*
可以在参数声明类型为void *的地方传递,因为void *是通用的。 但是,void **不是。 所以自动铸造失败了。