为什么使用函数名作为函数指针等效于将address-of运算符应用于函数名?

时间:2012-08-28 02:50:12

标签: c++ syntax function-pointers

有趣的是,使用函数名称作为函数指针的等同于将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).

3 个答案:

答案 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)()之类的表单,同时仍然允许*aint 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的类型是什么?没有其他可能性。