任何人都可以解释什么是函数指针以及为什么在外行术语中需要它们。在c语境中,请?
答案 0 :(得分:2)
在幕后,函数只是程序二进制机器代码中的一个位置。当您在C中使用函数时,编译器会生成在传入函数参数后跳转到该特定位置的指令。
函数指针是可用于保存函数位置的变量。这允许您的代码的一部分确定代码的另一部分中使用的函数。例如,qsort函数接受一个函数指针,用于确定要排序的对象的顺序。
答案 1 :(得分:1)
指针是内存的地址。
一个函数指针,指示函数代码开始的内存中的地址。
通常,您在编译时知道要调用哪个函数,因此请按名称引用它。编译代码时,编译器将该名称替换为实际机器代码的(通常是相对的)地址。
但有时您不知道在编译时要调用哪个函数。您可以使用开关或其他东西来调用不同的功能:
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 对于parens(“const void *,const void *)”,然后将 left 返回到它返回的int。第一组parens是必要的,以防止这声明一个函数返回指向int的指针。
然后我们可以使用address-of运算符(“&”)将函数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)/ 每个元素有多大? /, foo);
无论哪种方式,qsort
现在都会使用foo
来比较数组中的数字,以便对它们进行排序。 (比较器函数应返回特定值以允许发生这种情况,这超出了本讨论的范围,但一般来说,* 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_foo
)的,而且你(可能)没有办法重新编译qsort
来让它知道foo
(或reverse_foo
)。但是由于函数指针,qsort
可以调用foo
,尽管两个函数由不同的编码器分开编写。
答案 2 :(得分:0)
函数指针就像任何其他指针一样,除了它指向一个函数(代码)。
有许多用途 - 例如,您可以使用结构表实现网络协议的消息处理程序,每个结构表包含指向处理函数的指针,以及用于标识每条消息的其他相关数据。然后,当收到消息时,您可以查找相应的函数并通过表的指针调用它。
答案 3 :(得分:0)
函数指针指向特定函数的代码的二进制部分。
我用过它们的唯一一次是使用pthreads。当你启动一个线程时,你需要告诉它从哪里开始执行,所以你要给它一个指向它应该开始执行的函数的指针。本质上,该函数成为线程的“main()”,并且一旦它从该函数返回,线程就会死掉。
如果没有函数指针,就无法告诉pthreads开始执行新线程的位置。