使用和解除引用(void **)

时间:2013-09-23 04:34:35

标签: c pointers void-pointers pointer-to-array

我想传递一个指向函数的“多态”数组。

我可以在没有警告的情况下执行以下操作:

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}}数组等

3 个答案:

答案 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中没有通用的指向指针类型。

参考:C FAQ Question 4.9

答案 2 :(得分:0)

简短的回答是:任何类似于

的东西
<datatype>* <variable_name>

可以在参数声明的类型为void *的地方传递,因为void *是通用的。但是,void **不是。所以自动铸造失败了。