为什么 c 中的函数指针根本不必是指针?

Why does function pointer in c does not have to be pointer at all?

有这个:

#include <stdio.h>
#include <stdlib.h>

int do_op(int (*op)(int,int),int a, int b){ return op(a,b); }
/*int do_op(int (op)(int,int),int a,int b){return op(a,b);} */
int add(int a, int b){ return a+b; }
int mul(int a, int b){ return a*b; }

int main(){
    printf("add:%i;mul:%i\n",do_op(add,5,10),do_op(mul,5,10));
}

据我目前对函数指针的了解,它们的 "type" 是 return 值的类型。 (不知道它是如何在 gas 中实现的,return 值是否在 ret 之前的 %rax 中?只是一个细节),但是对函数的引用有什么意义,什么时候根本不需要参考?当它是 而不是 指针时,这是什么意思? (like (op)),那么value使用的函数是不是地址(不是address)?但是一般的函数是没有的,只有%rbi的起始地址,结束后又被ret调回到上层函数,所以在 c 中,函数 "pointer" 不是 pointer 是什么意思? (请举一些例子)

问题与代码中的注释有关,其中 (op) 部分不是指针,但仍然有效。那到底是不是指针呢?

函数指针与数据指针的不同之处在于它们指向代码,而不是数据。所以指针的 value 将成为函数开头的内存位置。由于 value 已经在内存中并且是地址,因此没有理由像普通指针那样对它进行引用。

如果您想了解更多详细信息,这篇文章似乎通过很好的示例对概念进行了清晰的解释: Function Pointers in C - GeeksforGeeks

函数指针的类型不是它的 return 类型。它是指向的函数的类型。

在参数int (*op)(int,int)的情况下,op的类型是"pointer to function which takes an int and an int, and returns int"。

您也可以将参数定义为 int op(int,int),在这种情况下 op 的类型是 "function which takes an int and an int, and returns int"。

因为函数指针指向代码,所以它们没有对象那样的 "value"。事实上,在任何地方你指定一个带有函数类型的表达式,它都会自动转换为一个指向函数的指针。所以你可以将参数 op 声明为 int (*op)(int,int)int op(int,int) 并且它们将完全相同。

C standard 的第 6.3.2.1p4 节说明了以下有关函数类型的内容:

A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.

第 6.7.6.3p8 节还说明了以下关于函数类型作为参数的内容:

A declaration of a parameter as ‘‘function returning type’’ shall be adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.

正因为如此,函数类型的参数才被允许。不是参数的函数类型的变量是没有用的,因为它不能被初始化或赋值。

c 中的函数指针始终是指向函数第一条指令的指针。
c中的函数值(将*应用于函数指针的值)也与函数指针一样实现,导致这种混淆。
最后,函数将始终是指向代码的指针,编译器只是忽略您使用的是 c 函数指针还是值。

From what I know about function pointer so far, is their "type" is of return value's type.

来自 C 标准(6.2.5 类型)

A function type is characterized by its return type and the number and types of its parameters.

例如这些函数的类型

int add(int a, int b){ return a+b; }
int mul(int a, int b){ return a*b; }

int( int, int )。那就是描述一个函数,你必须指定它接受什么以及它接受什么 returns.

What does it mean, when it is not pointer? (like (op))

在此声明中

int do_op(int (op)(int,int),int a,int b){return op(a,b);}

参数 op 的类型为 int( int, int )。编译器将具有函数类型的参数调整为具有指向函数的指针类型的参数。

例如这两个声明

int do_op(int (op)(int,int),int a,int b);
int do_op(int (*op)(int,int),int a,int b);

可以重写而无需像

这样的参数名称
int do_op(int (int,int),int ,int );
int do_op(int (*)(int,int),int ,int );

是等价的,声明了同一个函数。您可以在程序中包含这两个声明,尽管编译器会发出警告,指出存在冗余声明。

来自 C 标准(6.7.6.3 函数声明符(包括原型))

8 A declaration of a parameter as ‘‘function returning type’’ shall be adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.

当像本语句中那样将函数用作参数时

printf("add:%i;mul:%i\n",do_op(add,5,10),do_op(mul,5,10));

然后它被隐式转换为指向函数的指针。指针的值是可以传递控制权的函数入口点。

来自 C 标准(6.3.2.1 左值、数组和函数指示符)

4 A function designator is an expression that has function type. Except when it is the operand of the sizeof operator65) or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.

From what I know about function pointer so far, is their "type" is of return value's type.

没有。我知道我们已经在评论和回答您之前的一些问题时解决了这个问题。函数指针的类型不同于指向函数的 return 类型,也不同于指向函数的 return 类型的指针。函数指针的类型是特定的函数指针类型。所有函数指针类型都有一个 return 类型作为它们的属性之一。它们还传达有关函数参数的数量和类型的信息。函数指针类型名称也不同于所有对象指针类型名称。在本例中,类型名称是 int (*)(int,int),我相信您看到的与 intint *.

不同

what is the point of a reference to a function, when it does not have to be reference at all?

使用函数指针(不是"reference")的原因是允许在运行时选择不同的实际函数。在您的情况下,可以对函数 do_op() 进行不同的调用以执行不同的操作。这在这个例子中没什么大不了的,因为 do_op() 除了调用指定的函数一次什么都不做,并且操作的选择被硬编码到每次调用中,但是如果操作的选择是由用户输入决定。

当然函数指针参数对应的参数必须是(兼容的)函数指针。在这种情况下,C 不会对其类型匹配规则做出任何例外。

What does it mean, when it is not pointer? (like (op)),

但它一个指针。只要函数类型的表达式出现在有效的 C 表达式中,而不是作为一元 & 运算符的操作数,它就会自动转换为指向它标识的函数的指针。这也适用于被调用函数的标识符:函数调用运算符 () 是函数 pointers 上的运算符。您可以将此视为一项便利功能:您无需使用 & 运算符来获取函数指针。这使得代码更容易编写和阅读。 C 不提供任何方式来表达对函数值的访问。

The question is relating to the comment in the code, where the (op) part is not a pointer, but still work. So is it a pointer or not?

函数 do_op() 的参数 op 是一个指向函数的指针,该函数需要两个类型为 int 和 return 和 int 的参数。在对该函数的每次调用中,相应的参数是一个函数标识符。作为函数类型的表达式,它们会自动转换为指针。生成的函数指针属于预期类型。