为什么使用函数名称作为函数指针相当于将函数名称的地址运算符?
有趣的是, 使用函数名称作为函数指针相当于将地址 – 运算符应用于函数名称 !
这里是例子。
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!
这似乎不符合该语言的其他部分。 这个devise的基本原理是什么?
这个问题解释了这种行为的语义以及它为什么起作用。 但是我对这种语言的devise感兴趣。
更有意思的是函数types在作为参数使用时可以被隐式转换为指向自身的指针,但是在作为返回types使用时不会被转换为指向自身的指针!
例:
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).
既然你特别要求这个行为的基本原理,这里是我能find的最接近的东西(从ANSI C90理论基础文档 – http://www.lysator.liu.se/c/rat/c3.html#3-3- 2-2 ):
3.3.2.2函数调用
指向函数的指针可以用作
(*pf)()
或用作pf()
。 后者的结构,在基础文件中没有批准,出现在C的一些现有版本中,是明确的,使旧的代码无效,并且可以是重要的速记。 简写对于仅显示一个外部名称的包来说很有用,它指定了一个充满指向对象和函数指针的结构:成员函数可以被调用为graphics.open(file)
而不是(*graphics.open)(file)
。 函数指示符的处理可能导致一些好奇而有效的句法forms。 鉴于声明:int f ( ) , ( *pf ) ( ) ;
那么以下所有expression式都是有效的函数调用:
( &f)(); f(); (*f)(); (**f)(); (***f)(); pf(); (*pf)(); (**pf)(); (***pf)();
前一段讨论了每一行的第一个expression式。 其次是传统用法。 在几乎所有的expression式上下文中,所有后续expression式都利用了函数指示符的隐式转换为指针值。 委员会认为这些表格并没有真正的危害。 像
(*f)()
这样的外挂forms,而仍然允许*a
(对于int a[])
,看起来更麻烦。
基本上,函数指示符和函数指针之间的等价性被加上来使得使用函数指针更方便一些。
这是从Cinheritance的function
在C语言中,主要是因为函数的名字本身没有多大意义。 所有你可以用一个实际的function做的就是调用它。 如果你不打电话, 唯一可以做的就是取地址。 由于没有歧义,任何时候函数名称后面都不会跟一个(
表示对该函数的调用,该名称将评估为该函数的地址。
这实际上有点类似于语言的另一部分 – 除非在一些相当有限的情况下(用作&
或sizeof
的操作数),否则数组的名称将计算为数组的第一个元素的地址。
由于C允许它,所以C ++也是如此,主要是因为同样的事情仍然是正确的:你可以做的唯一的事情就是调用它或者获取它的地址,所以如果这个名字后面没有一个(
表示一个函数调用,那么这个名字的评估地址是不含糊的。
对于数组,当使用地址 – 运算符时没有指针衰减:
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]
这是有道理的,因为数组和指针是不同的types,例如可以返回对数组的引用或者传递对函数中数组的引用。
但是,有了function,还有什么其他types的可能?
void foo(){} &foo; // #1 foo; // #2
假设只有#2给出typesvoid(*)()
,那么&foo
的types是什么? 没有其他的可能性。