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

WiS*_*GaN 16 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;
}
Run Code Online (Sandbox Code Playgroud)

使用这个名称是我们在数组中已经知道的.但是你不能写出类似的东西

int a[2];
int * b = &a; // Error!
Run Code Online (Sandbox Code Playgroud)

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

这个问题解释了这种行为的语义及其工作原理.但是我对这种语言设计的原因很感兴趣.

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

例:

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).
Run Code Online (Sandbox Code Playgroud)

Mic*_*urr 16

既然你明确要求这种行为的基本原理,这里是我能找到的最接近的东西(来自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).函数指示符的处理可以导致一些好奇但有效的句法形式.鉴于声明:

int f ( ) , ( *pf ) ( ) ; 
Run Code Online (Sandbox Code Playgroud)

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

( &f)(); f(); (*f)(); (**f)(); (***f)();
pf(); (*pf)(); (**pf)(); (***pf)();
Run Code Online (Sandbox Code Playgroud)

上一段讨论了每一行的第一个表达方式.第二种是传统用法.在几乎所有表达式上下文中,所有后续表达式都利用函数指示符到指针值的隐式转换.委员会认为允许这些表格没有任何实际损害; 禁止形式(*f)(),但仍然允许*a(因为int a[]),似乎比它的价值更麻烦).

基本上,添加了函数指示符和函数指针之间的等价来使函数指针更方便一些.


Jer*_*fin 11

这是继承自C的功能.

在C中,它主要是因为函数的名称本身并不重要.您可以使用实际功能进行调用.如果你没有打电话,你唯一能做的就是拿地址.由于没有歧义,任何时候函数名称后面都没有(表示对函数的调用,名称将计算为函数的地址.

这实际上有点类似于语言的另一部分 - 数组的名称求值为数组的第一个元素的地址,除非在一些相当有限的情况下(用作&或的操作数sizeof).

既然C允许它,C++也可以这样做,主要是因为同样的事情仍然存在:你可以用函数做的唯一事情就是调用它或取其地址,所以如果名字后面没有(表示函数调用,然后名称评估地址没有歧义.

  • 从技术上讲,在C语言中,即使在函数调用表达式中使用*时,函数名称也等于函数的地址。“表示被调用函数的表达式”必须具有指向函数的指针类型,为了适应这种情况,裸函数名称将作为指向函数的指针进行评估“,除非它是`sizeof`或一元`的操作数。 ”(分别为C99§§6.5.2.2p1和6.3.2.1p4)。 (3认同)