有趣的是,使用函数名称作为函数指针的等同于将address-of运算符应用于函数名称!
这是一个例子。
typedef bool (*FunType)(int);
bool f(int);
int main() {
FunType a = f;
FunType b = &a; // Sure, here's an error.
FunType c = &f; // This is not an error, though.
// It's equivalent to the statement without "&".
// So we have c equals a.
return 0;
}
使用名称是我们在数组中已经知道的。但你不能写像
这样的东西int a[2];
int * b = &a; // Error!
这似乎与该语言的其他部分不一致。这个设计的基本原理是什么?
This question explains the semantics of such behavior and why it works.但我对这种语言的设计方式感兴趣。
更有趣的是,当用作参数时,函数类型可以隐式转换为指向自身的指针,但在用作返回类型时不会转换为指向自身的指针!
示例:
typedef bool FunctionType(int);
void g(FunctionType); // Implicitly converted to void g(FunctionType *).
FunctionType h(); // Error!
FunctionType * j(); // Return a function pointer to a function
// that has the type of bool(int).
答案 0 :(得分:16)
由于您特别询问此行为的基本原理,这里是我能找到的最接近的内容(来自ANSI C90 Rationale文档 - http://www.lysator.liu.se/c/rat/c3.html#3-3-2-2):
3.3.2.2函数调用
指向函数的指针可以用作
(*pf)()
或pf()
。 后一种结构,未在基础文件中批准,出现在 一些现有版本的C,是明确的,没有旧代码无效, 并且可以是一个重要的速记。速记很有用 只包含一个外部名称的包,它指定一个 结构充满指向对象和函数的指针:member 函数可以被称为graphics.open(file)
而不是。{(*graphics.open)(file)
。功能指示符的处理可以 导致一些好奇但有效的句法形式。鉴于 声明:int f ( ) , ( *pf ) ( ) ;
然后所有以下表达式都是有效的函数调用:
( &f)(); f(); (*f)(); (**f)(); (***f)(); pf(); (*pf)(); (**pf)(); (***pf)();
前面讨论了每一行的第一个表达式 段落。第二种是传统用法。随后都是 表达式利用了函数的隐式转换 几乎所有表达式上下文中的指针值的指示符。 委员会认为允许这些表格没有任何实际损害;取缔
(*f)()
之类的表单,同时仍然允许*a
(int a[])
, 只是看起来比它的价值更麻烦。
基本上,添加了函数指示符和函数指针之间的等价,使得使用函数指针更加方便。
答案 1 :(得分:9)
这是继承自C的功能。
在C中,它主要是因为函数的名称本身并不重要。您可以使用实际功能进行调用。如果你没有打电话,你可以做的只有 的事情就是拿地址。由于没有歧义,任何时候函数名称后面没有(
来表示对函数的调用,名称将计算为函数的地址。
这实际上有点类似于语言的另一部分 - 数组的名称求值为数组的第一个元素的地址,除非在一些相当有限的情况下(用作{{1}的操作数) }或&
)。
由于C允许它,C ++也是如此,主要是因为同样的事情仍然存在:你可以用函数做的唯一事情就是调用它或者取其地址,所以如果名字后面没有{{1表示函数调用,然后名称评估为地址而没有歧义。
答案 2 :(得分:2)
对于数组,当使用address-of运算符时,没有指针衰减:
int a[2];
int * p1 = a; // No address-of operator, so type is int*
int (*p2)[2] = &a; // Address-of operator used, so type is int (*)[2]
这是有道理的,因为数组和指针是不同的类型,例如,可以返回对数组的引用或将引用传递给函数中的数组。
但是,对于功能,还有什么其他类型?
void foo(){}
&foo; // #1
foo; // #2
让我们假设只有#2给出类型void(*)()
,&foo
的类型是什么?没有其他可能性。