20

有趣的是,使用函数名作为函数指针相当于将地址运算符应用于函数名

这是示例。

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!

它似乎与语言的其他部分不一致。这种设计的基本原理是什么?

这个问题解释了这种行为的语义以及它为什么起作用。但我感兴趣的是为什么这种语言是这样设计的。

更有趣的是,函数类型在作为参数使用时可以隐式转换为指向自身的指针,但在作为返回类型使用时不会转换为指向自身的指针!

例子:

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).
4

3 回答 3

20

由于您特别询问这种行为的基本原理,这是我能找到的最接近的东西(来自 ANSI C90 基本原理文档 - http://www.lysator.liu.se/c/rat/c3.html#3-3- 2-2 ):

3.3.2.2 函数调用

指向函数的指针可以用作 as(*pf)()或 as pf()。后一种结构在基础文档中没有得到认可,出现在一些当前版本的 C 中,是明确的,不会使旧代码无效,并且可以是重要的速记。简写对于只显示一个外部名称的包很有用,它指定一个充满指向对象 s 和函数的指针的结构:成员函数可以被称为graphics.open(file)而不是 (*graphics.open)(file). 函数指示符的处理可能会导致一些奇怪但有效的句法形式。鉴于声明:

int f ( ) , ( *pf ) ( ) ; 

那么以下所有表达式都是有效的函数调用:

( &f)(); f(); (*f)(); (**f)(); (***f)();
pf(); (*pf)(); (**pf)(); (***pf)();

每行的第一个表达式在前一段中讨论过。二是常规用法。在几乎所有的表达式上下文中,所有后续表达式都利用函数指示符到指针值的隐式转换。委员会认为允许这些表格并没有真正的危害;取缔形式之类(*f)()的,虽然仍然允许*a(因为int a[]),只是看起来比它的价值更麻烦。

基本上,添加了函数指示符和函数指针之间的等价性,以使使用函数指针更加方便。

于 2012-08-28T03:43:42.353 回答
13

这是从 C 继承的特性。

在 C 语言中,它是允许的,主要是因为函数名本身并没有太多其他含义。你可以用一个实际的函数做的就是调用它。如果你不打电话,你唯一能做的就是获取地址。由于没有歧义,任何时候函数名后面没有跟 a(来表示对该函数的调用,该名称的计算结果就是函数的地址。

这实际上有点类似于语言的其他部分——数组的名称计算为数组的第一个元素的地址,除非在一些相当有限的情况下(用作&or的操作数sizeof)。

由于 C 允许,C++ 也可以这样做,主要是因为同样如此:你可以对函数做的唯一事情是调用它或获取它的地址,所以如果名称后面没有(表示函数调用的 a,然后名称计算为地址,没有歧义。

于 2012-08-28T02:57:53.360 回答
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 给出了 type void(*)(),那么 type 会&foo是什么?没有其他可能。

于 2012-08-28T04:17:29.243 回答