为什么函数指针定义可以使用任意数量的“&”或星号“ *”?


216

为什么要进行以下工作?

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();
}

Answers:


224

这样做有几个方面,使所有这些运算符组合可以相同的方式工作。

所有这些工作的根本原因是一个函数(如foo)可以隐式转换为指向该函数的指针。这就是void (*p1_foo)() = foo;工作原理: foo将其隐式转换为指向自身的指针,并将该指针分配给p1_foo

一元&函数在应用于函数时会产生指向函数的指针,就像在将其应用于对象时会产生对象的地址一样。对于指向普通函数的指针,由于隐式的函数到函数指针的转换,它总是多余的。无论如何,这就是为什么void (*p3_foo)() = &foo;可行。

一元 *变量在应用于函数指针时会产生指向对象的函数,就像将其应用于指向对象的普通指针时会产生指向对象一样。

这些规则可以合并。考虑您倒数第二个示例**foo

  • 首先,foo将其隐式转换为指向自身的指针,然后将第一个*应用于该函数指针,foo再次产生该函数。
  • 然后,将结果再次隐式转换为指向自身的指针,并*应用第二个指针,再次产生函数foo
  • 然后将其再次隐式转换为函数指针,并分配给该变量。

您可以根据需要添加任意多个*,结果始终相同。*s 越多,越好。

我们也可以考虑您的第五个示例&*foo

  • 首先,foo被隐式转换为指向自身的指针;一元*应用,foo再次屈服。
  • 然后,将&应用于foo,产生指向的指针foo,该指针已分配给该变量。

尽管&只能应用于函数,而不能应用于已转换为函数指针的函数(当然,除非函数指针是变量,在这种情况下,结果是指向指针的指针-功能;例如,您可以将其添加到列表中void (**pp_foo)() = &p7_foo;)。

这就是为什么&&foo不起作用的 原因&foo。它是一个作为右值的函数指针。但是,它&*&*&*&*&*&*foo也可以工作,&******&foo因为在这两个表达式中,&始终将应用于函数而不是将rvalue应用于函数指针。

还要注意,您不需要使用一元*函数通过函数指针进行调用;双方(*p1_foo)();(p1_foo)();有再次因为函数到函数指针转换的结果相同。


2
@Jimmy:这些不是对函数指针的引用,它们只是函数指针。 &foo接受的地址foo,这导致函数指针指向foo,正如人们所期望的那样。
2011年

2
您也不能链接&对象的运算符:给定int p;&p产生指向的指针,p并且是右值表达式;该&运算符需要一个左值表达式。
James McNellis 2011年

12
我不同意。越多*快乐
塞斯·卡内基

28
请不要编辑我的示例的语法。我选择了非常具体的示例来演示语言的功能。
James McNellis 2012年

7
附带说明一下,C标准明确指出&*相互抵消的组合(6.5.3.2):"The unary & operator yields the address of its operand."/-/ "If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue."
伦丁2015年

9

我认为记住C只是底层计算机的抽象也是很有帮助的,这是抽象泄漏的地方之一。

从计算机的角度来看,功能只是一个内存地址,如果执行该功能,它将执行其他指令。因此,C语言中的函数本身被建模为地址,这可能导致设计将函数与其指向的地址“相同”。


0

&并且 *是在C中声明为函数的符号上的幂等运算,这意味着func == *func == &func == *&func并且因此*func == **func

这意味着,类型int ()相同int (*)()作为函数参数和定义的FUNC可以如通过*funcfunc&func(&func)()与相同func()Godbolt链接。

函数是一个真正的地址,因此*&没有任何意义,而不是产生一个错误,编译器选择将其解释为FUNC的地址。

&但是在声明为函数指针的符号上获取指针的地址(因为它现在具有单独的用途),而funcp*funcp相同

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.