为什么函数指针可以带或不带运算符地址使用?

Why can function pointers be used with or without the address of operator?

在书"Beginning C from Novice to Professional"中,作者在将函数赋值给函数指针时没有使用运算符的地址。我在我的编译器上输入了带有和不带有运算符地址的代码,并且两次都按预期编译和执行。为什么会这样,在 enterprise/business 设置中首选哪种方式?

int sum(int, int);

int main(void)
{
    ...
    int (*pfun)(int, int);
    pfun = ∑
    pfun = sum;
    ...
}

int sum(int x, int y)
{
    return x + y;
}

这是 C 函数的一个特点。C 标准规定如下 (C11 3.4.1p4):

  1. A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, 65) or the unary & operator, a function designator with type ''function returning type'' is converted to an expression that has type ''pointer to function returning type''.

即作为函数指示符的 sumany 表达式上下文中,除非前面有 & 或上述 2 个运算符被转换为指向函数的指针。当然在表达式 &sum 中,结果是一个指向函数的指针。并且 ISO C 不允许将 sizeof_Alignof 应用于函数,因此在编译的 any 表达式中,函数指示符要么是隐式的,要么是在地址运算符的情况,显式转换为指向函数的指针。

甚至函数调用运算符 () 要求它的操作数是一个函数指针,因此您可以在不取消引用的情况下调用 pfunpfun(1, 2);而在sum(1, 2)sum转换为函数指针,然后函数调用运算符作用于这个指针。

有编码约定说通过函数指针的调用应该使用取消引用运算符 *,即 (*pfun)(1, 2),同样,赋值应该写成 pfun = ∑

因此,写成 (*pfun)(1, 2) 并不能更清楚地表明它是一个指针,因为相同的语法同样适用于函数指示符,即 (*sum)(1, 2);在后者中,sum 首先转换为指向函数的指针,因为它是 * 的操作数;然后解引用再次将指向函数的指针转换为函数指示符,然后由于它是函数调用运算符的操作数,因此再次转换为函数指针。

最后,注意pfun 作为函数指针类型的对象&pfun实际上会得到指针变量的地址,这几乎是从来没有你想要的。