【问题标题】:what are function pointers [duplicate]什么是函数指针[重复]
【发布时间】:2010-07-16 20:00:07
【问题描述】:

可能重复:
What is the point of function pointers?

任何人都可以用外行术语解释什么是函数指针以及为什么需要它们。请问在c上下文中?

【问题讨论】:

标签: c function-pointers


【解决方案1】:

在底层,函数只是程序二进制机器码中的一个位置。当您在 C 中使用函数时,编译器会在传入函数的参数后生成跳转到特定位置的指令。

函数指针是一个变量,可以用来保存函数的位置。这允许您的代码的一部分确定在您的代码的另一部分中使用什么函数。例如,qsort 函数采用一个函数指针,您可以使用该指针来确定被排序对象的顺序。

【讨论】:

  • 所以你不知道在运行时调用哪个函数,你做一些比较并调用适当的函数。我说的对吗?
  • 我想你已经明白了。例如,使用 qsort,您可以根据用户输入选择升序或降序。
【解决方案2】:

指针是内存的地址。

函数指针指向函数代码开始的内存地址。

通常,您在编译时就知道要调用什么函数,因此您可以通过名称来引用它。当代码 si 被编译时,编译器会将该名称替换为实际机器代码的(通常是相对的)地址。

但有时您不知道在编译时要调用什么函数。您可以使用开关或其他东西来调用不同的功能:

switch(c) {
  case '+' : add( op1, op2); break;
  case '*' : multiple( op1, op2); break;
  case '/'  : divide(op1, op2); break;
}

但这很乏味且容易出错。

或者您可能正在编写一个库函数,例如qsort,它知道如何对任何类型进行排序,但需要一个比较器函数来进行排序。这样我们就不必打开并重新编译 qsort,qsort 允许我们将我们希望它用来比较我们的用户定义类型的代码(即函数)传递给它。

因此,C(和 C++)允许获取该代码的地址——函数的地址——。取地址会产生一个指向函数的类型指针的值(实际上是指向函数类型的类型指针,其中函数的签名的类型——即类型以及它的参数数量——以及它的返回类型,它返回的对象的类型。(注意,签名不包括返回类型,而是该函数包括两个签名和返回类型。)

无论如何,这个产生的值当然可以分配给一个兼容类型的变量——一个指向函数的指针,并像任何其他变量一样传递或复制,因为它毕竟只是一个数字,一个内存中的地址。

假设我们有一个函数 foo,返回类型为 int,签名为 const void*, const void*:

 int foo( const void* lhs, const void* rhs);

我们可以创建一个该类型的变量:

 int ( *foopointer) ( const void*, const void* ) ;

是的,真的,这是一个变量声明!将其读作“foopointer 是一个指向具有两个 const void 指针并返回 int 的函数的指针”,通过读取名称(“foopointer”)然后向左到指针(“*”),然后 right到括号 ("const void*, const void*)",然后返回 left 到它返回的 int。第一组括号是必要的,以防止 this 声明返回指向 int 的指针的函数。

然后我们可以使用地址运算符(“&”)将函数 foo 的地址分配给变量 foopointer:

  foopointer = &foo;

实际上,地址操作符并不是绝对必要的,如果我们不使用它,它是隐含的,但使用它来明确您正在获取地址。它可以帮助读者。

然后我们可以使用foopointer,比如说调用qsort:

  int some_array_of_int[] = { 1, 3, 2 ) ;
  qsort( some_array_of_int, 
        3 /* elements */, 
        sizeof(int) /*each element is how big?*/, 
        foopointer) ;

当然,我们可以直接使用 foo: qsort(some_array_of_int, 3 /* 元素 */, sizeof(int) /每个元素有多大?/, 富);

无论哪种方式,qsort 现在将使用foo 来比较我们数组中的数字,以便对它们进行排序。 (比较器函数应该返回特定的值以允许这种情况发生,这超出了本次讨论的范围,但一般来说,*lhs - *rhs)。

现在我们还没有指定 foo 是如何排序的,但是我们不必为了 reverse 它的排序方式,因为我们可以返回 foo 的否定返回值:

 int reverse_foo( const void* lhs, const void* rhs) {
    return - foo( lhs, rhs ) ;
 }

现在我们可以在运行时决定是升序还是降序排序或列出:

  bool reverse = get_reverse_from_user_or_somthing();

  qsort( some_array_of_int, 
         3 /* elements */, 
         sizeof(int) /*each element is how big?*/, 
         reverse ? reverse_foo : foo ) ;

写 qsort 的人不知道你会如何写 foo(和 reverse_foo),而且你(可能)没有办法重新编译 qsort 让它知道 foo(或 @ 987654336@)。但是由于函数指针,qsort 可以调用 foo,尽管这两个函数是相隔多年编写的,由不同的编码人员编写。

【讨论】:

    【解决方案3】:

    函数指针与任何其他指针一样,只是它指向一个函数(代码)。

    有很多用途 - 例如,您可以通过使用结构表来实现网络协议的消息处理程序,每个结构表都包含指向处理程序函数的指针,以及用于标识每条消息的其他相关数据。然后当收到消息时,您可以查找相应的函数并通过表的指针调用它。

    【讨论】:

    • 所以你不知道在运行时调用哪个函数,你做一些比较并调用适当的函数。我说的对吗?
    【解决方案4】:

    函数指针指向特定函数的二进制代码段。

    我唯一一次使用它们是使用 pthreads。当你启动一个线程时,你需要告诉它从哪里开始执行,所以你会给它一个指向它应该开始执行的函数的指针。本质上,那个函数变成了线程的“main()”,并且一旦它从那个函数返回,线程就会死掉。

    没有函数指针,您无法告诉 pthread 从哪里开始执行新线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 2011-09-30
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多