C 什么是函数指针

C 什么是函数指针,c,function-pointers,C,Function Pointers,可能重复: 谁能解释一下什么是函数指针,为什么需要外行术语。在c上下文中,请?在引擎盖下,函数只是程序二进制机器代码中的一个位置。在C中使用函数时,编译器会生成指令,在传入函数的参数后跳转到该特定位置 函数指针是一个变量,可以用来保存函数的位置。这允许代码的一部分确定代码的另一部分使用的函数。例如,函数采用一个函数指针,您可以使用它来确定被排序对象的顺序。函数指针与任何其他指针一样,只是它指向一个函数(代码) 有很多用途-例如,您可以通过使用结构表来实现网络协议的消息处理程序,每个结构表包含指

可能重复:


谁能解释一下什么是函数指针,为什么需要外行术语。在c上下文中,请?

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


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

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


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

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

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


没有函数指针,就无法告诉pthreads新线程从何处开始执行。

指针是内存地址

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

通常,在编译时,您知道要调用什么函数,所以可以按名称引用它。编译代码时,编译器会用实际机器代码的地址(通常是相对地址)替换该名称

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

switch(c) {
  case '+' : add( op1, op2); break;
  case '*' : multiple( op1, op2); break;
  case '/'  : divide(op1, op2); break;
}
但这是乏味和容易出错的

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

所以C(和C++)允许获取代码的地址——函数的地址。获取地址会产生一个类型为pointer to function的值(实际上是类型pointer to function of type的值,其中函数签名的类型——即其参数的类型和数量——及其返回类型,即它返回的对象的类型)。(请注意,签名不包括返回类型,但函数的类型包括签名和返回类型。)

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

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

 int foo( const void* lhs, const void* rhs);
我们可以创建该类型的变量:

 int ( *foopointer) ( const void*, const void* ) ;
是的,真的,这是一个变量声明!通过读取名称(“foopointer”)将其理解为“foopointer是指向一个函数的指针,该函数使用两个const void指针并返回int”,然后向左读取指针(“*”),然后向右读取参数(“const void*,const void*)”,然后返回到它返回的int。第一组参数是防止它声明返回指向int的指针的函数所必需的

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

实际上,操作符的地址并不是绝对必要的,如果我们不使用它,它是隐含的,但使用它可以清楚地表明您正在使用一个地址。它有助于读者

然后我们可以使用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(一些数组或整数, 3/*元素*/,, sizeof(int)/每个元素有多大?/, (富),

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

现在我们还没有指定如何
foo
对事物进行排序,但我们不必为了反转它的排序方式而指定,这样我们就可以返回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\u-foo
),而且你(可能)没有办法重新编译
qsort
,让它知道
foo
(或
reverse\u-foo
)但是多亏了函数指针,
qsort
可以调用
foo
,尽管这两个函数是由不同的代码编写者编写的。

我建议你查阅你的C语言书;如果你没有,我建议你读一本.dup:@eruciform中列出的入门书,这有点蹩脚,直接链接到o你自己在一个问题上的回答,这个问题本身就被当作一个问题来解决duplicate@tyler:新这里-不知道这是禁忌。我甚至没有看到另一个已经关闭,我只是记得几天前的内容并发布了它。真正的dup:“重复”问题是“函数指针有什么用”;这是“函数指针是什么”,这是为了实现,而不是为了使用-
  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 ) ;