使用和解除引用(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 **不是。 所以自动铸造失败了。