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

为什么c中的函数指针根本不必是指针?,c,function-pointers,implicit-conversion,function-declaration,C,Function Pointers,Implicit Conversion,Function Declaration,具有以下特征: #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){ retur

具有以下特征:

#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));
}
据我所知,函数指针的类型是返回值的类型。不知道它是如何在gas中实现的,返回值是否在ret之前以%rax为单位?只是一个细节,然而,当函数不一定是引用时,引用函数的意义是什么?当它不是指针时,它意味着什么?和op一样,value使用的函数不是address吗?但函数通常没有值,它只有%rbi中的起始地址,在它完成后,它会被ret返回到上一个函数,那么在c中,函数指针不是指针是什么意思呢?请举几个例子


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

函数指针与数据指针的不同之处在于它们指向代码,而不是数据。因此指针的值将成为函数开头的内存位置。由于该值已经存在于内存中,因此没有理由像对待普通指针那样遵从它

如果您想了解更多细节,本文似乎有一个清晰的概念解释,并提供了很好的示例:
函数指针的类型不是其返回类型。它是指向的函数的类型

对于参数int*opint,int,op的类型是指向函数的指针,该函数接受int和int,并返回int

您还可以将参数定义为int opint,在这种情况下,op的类型是接受int和int并返回int的函数

因为函数指针指向代码,所以它们没有对象所具有的值。事实上,在指定函数类型的表达式的任何地方,它都会自动转换为指向函数的指针。因此,您可以将参数op声明为int*opint,int或int-opint,int,它们将完全相同

本手册第6.3.2.1p4节说明了以下有关功能类型的内容:

函数指示符是具有函数的表达式 类型除非它是sizeof运算符的操作数, 函数的_Alignof运算符或一元&运算符 类型为“函数返回类型”的指示符已转换为 具有类型“”的表达式,指向返回类型“”的函数的指针

第6.7.6.3p8节还将函数类型作为参数说明如下:

将参数声明为“函数返回类型”应为 调整为“函数返回类型指针”,如6.3.2.1所示


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

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

据我所知,函数指针的类型是 返回值的类型

来自C标准6.2.5类型

函数类型的特征是其返回类型、数量和 其参数的类型

例如,这些函数的类型

int add(int a, int b){ return a+b; }
int mul(int a, int b){ return a*b; }
是int,int。也就是说,要描述一个函数,您必须指定它接受什么和返回什么

当它不是指针时,它意味着什么?像op

在本声明中

int do_op(int (op)(int,int),int a,int b){return op(a,b);}
参数op的类型为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将参数声明为“函数返回类型”应为 调整为“函数返回类型指针”,如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函数指示符是具有函数类型的表达式。 除非它是sizeof运算符65或一元数的操作数& 运算符,类型为“函数返回类型”的函数指示符 这是康弗 ted指向具有类型“”指向函数指针的表达式 正在返回类型“”

据我所知,函数指针的类型是返回值的类型

不,我知道我们已经在对你之前的一些问题的评论和回答中提到了这个问题。函数指针的类型不同于指向函数的返回类型,也不同于指向函数的返回类型的指针。函数指针的类型是一种特定的函数指针类型。所有函数指针类型都有一个返回类型作为其属性之一。它们还传递有关函数参数数量和类型的信息。函数指针类型名称也不同于所有对象指针类型名称。在本例中,类型名是int*int,int,我相信您会看到它与int和int*都不同

当函数不一定是引用时,引用函数的意义是什么

使用函数指针not reference的原因是允许在运行时选择不同的实际函数。在您的情况下,可以对函数do_op进行不同的调用以执行不同的操作。在本例中,这没什么大不了的,因为do_op只调用指定的函数一次,操作的选择是硬编码到每个调用中的,但是如果操作的选择是由用户输入决定的,则更有趣

当然,与函数指针参数对应的参数必须是兼容的函数指针。在这种情况下,C对其类型匹配规则没有任何例外

当它不是指针时,它意味着什么?像op一样

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

问题与代码中的注释有关,其中op部分不是指针,但仍然有效。那么它到底是不是一个指针


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

问题文本对我来说没有多大意义,您是否可以指出您发布的代码中您不理解的部分?@Austics456不清楚您为什么决定函数指针不是指针?@M.M,在注释中,有一种替代方法,其中op部分不是*op,因此它不是pointer@autistic456在函数参数中,函数类型的参数被调整为指向-function@M.M但是,在某些情况下,不允许op->when函数返回函数:int*fintint,int是唯一的方法。我不能做int fintint,int,所以你不是100%正确。第一种情况*opint,int可以赋值,而第二种情况是函数声明。在我的例子中,它在另一个函数中用作参数,因此必须是可赋值的,但仍然不需要有*,它通常表示指针。因此,如果它总是指向代码的第一条指令,那么为什么它不必在可分配的上下文中使用*呢?@autistic456请参阅我的编辑。函数类型的参数与指向函数的指针相同。但是,在某些情况下,不允许op->when function返回函数:int*fintint,int是唯一的方法。我不能做int fintint,int,所以你不是100%正确。为什么它们相等?*int,int和int,int之间没有区别?我想有,我不知道编译器做什么,或者应用什么规则,但这两种类型不是相同的same@autistic456我在回答中写道,编译器将参数的类型从函数类型调整为指向函数的指针。但在此之前,当函数的值不存在时,怎么可能退出int,int?只有*intint才有意义,因为它实际上是指向指令第一个地址的指针,但前者没有意义sense@autistic456它是一种参数类型的声明,例如int,int与指定其他参数类型的方式相同。@Austics456当函数作为参数传递时,它将转换为指向其入口点的指针。C完全没有说明函数指针值如何对应于机器指令,我也没有看到任何其他类型的指令
你的意思可能是。你的想法很普通,但不是必须的。此外,函数值与函数指针完全不同,这与数组不是指针的方式非常相似。函数和数组都有自动转换,这并不意味着它们本身就是指针。@JohnBollinger然而,在某些情况下,op是不允许的->当函数返回函数时:int*fintint,int是唯一的方法。我不能做int fintint,int,所以你不是100%正确。@Austics456,我不知道你为什么认为C不允许声明一个返回函数的函数这一事实与我在这里所说的相矛盾。你的意思是向这个答案的作者Dani发表这个评论吗?@JohnBollinger这不是关于C做什么,问题是为什么在上面的例子中,*op和op都是有效的。但在这种情况下,我只是评论它是无效的。这两种情况contradics@autistic456,我没有说op和*op在语法上是可互换的。事实并非如此。特别是,它们在声明中是不可互换的。但我之前的所有评论都是关于它们在表达式中的使用,这就是你所问的,以及自动语义转换如何解释你在问题中强调的现象。OP似乎没有问为什么指针没有被取消引用。他们询问,为什么指定函数的标识符add和mul可以用作函数指针对应的参数,即使它们指定的是函数而不是指针。