传递函数指针

The*_*ian 18 c c++ pointers function parameter-passing

关于如何将指针传递给指针函数,我有点困惑.我有一个函数,它指向一个我理解没有问题的函数(ExecBlock).但是我给了另一个函数原型(ExecBlock2),它接受了解引用指针(我不确定它到底是什么),如果传递函数有任何参数,也会接受参数.如果有人可以解释优先级以及解释引用函数的确切内容.这不仅仅是传递函数本身吗?在这种情况下(void*)做什么?

int ExecBlock (void (*f) (void), int isSet)
{
    return ExecBlock2( HOW TO PASS HERE? , NULL, isSet);
}

int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
    ... more code
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Chr*_*ice 37

void (*f) (void)
Run Code Online (Sandbox Code Playgroud)

指向函数的指针,没有返回void的参数.

void *(*f)(void *)
Run Code Online (Sandbox Code Playgroud)

指向函数的指针获取void指针并返回void指针.

由于类型不同,编译器不允许您在不进行强制转换的情况下将一个传递给另一个.(请注意,在这里,强制转换并不是正确的答案,正如@detly指出的那样,会导致未定义的行为.)

至于解除引用函数的指针,您不必在函数指针之前显式地设置"*"来调用它.例如,您可以通过执行调用函数指针f

f();
Run Code Online (Sandbox Code Playgroud)

一个函数指针示例

假设您有一个函数f,您希望将其传递给一个名为的函数takes_a_function. takes_a_function可能会有类似的类型

void takes_a_function(void (*f)(void *data), void *data);
Run Code Online (Sandbox Code Playgroud)

注意有两个参数takes_a_function,一个函数指针和一个指向某些数据的void指针.另请注意,该函数f恰好将void指针作为参数.我们的想法是你可以传递数据takes_a_function,并将它传递给f.例如,takes_a_function可以定义为

void takes_a_function(void (*f)(void *), void *data) {
  f(data);
}
Run Code Online (Sandbox Code Playgroud)

现在,让我们编写一个函数来传递给takes_a_function.我们的函数只会打印一个传递给它的int.

void prints_an_int(void *data) {
  // The idiom for converting a void pointer to another kind
  // of pointer.  NO NEED TO CAST.  Note this behavior is only
  // defined if the pointer data really does point to an int.
  int *i = data;
  printf("%d", *i);
}

int i = 0;
takes_a_function(prints_an_int, &i);
Run Code Online (Sandbox Code Playgroud)

关于这个例子的几个关键点:

  • prints_an_int与期望的函数指针具有相同的类型takes_a_function.不需要施放.
  • 无需使用&运算符来创建对函数的引用.这就是为什么我们可以通过prints_an_inttakes_a_function直接.但我们也可以说takes_a_function(&prints_an_int, &i),它也是一样的.
  • void*基本上是指"未知类型的指针".要实际执行任何操作,必须将类型的变量分配给void*您期望的类型的另一个指针变量.如果您实际传入正确的指针类型,这只能保证工作!在这个例子中,我们可以分配data给一个int*,因为数据确实指向了一个int.如果你想要更多的数据而不仅仅是一个整数,一个常见的模式就是创建你自己的结构类型,它包含你想要的所有字段,然后传递它.
  • 作为一种特殊情况,编译器在将void指针分配给其他指针时不要求您进行强制转换,反之亦然.但是,如果最终将void指针转换回正确的类型,则只会获得定义的行为.