为什么函数指针定义适用于任意数量的&符号'&'或星号'*'?

Jim*_*mmy 204 c c++ function-pointers

为什么以下工作?

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

Jam*_*lis 210

有一些部分允许所有这些运算符组合以相同的方式工作.

所有这些工作的根本原因是函数(如foo)可以隐式转换为指向函数的指针.这就是为什么void (*p1_foo)() = foo;工作: foo被隐式转换为指向自身的指针,并指定指针p1_foo.

&当应用于函数时,一元会产生一个指向函数的指针,就像它在应用于对象时产生对象的地址一样.对于指向普通函数的指针,由于隐式的函数 - 函数 - 指针转换,它总是冗余的.无论如何,这就是为什么void (*p3_foo)() = &foo;有效.

*当应用于函数指针时,一元会产生指向函数,就像它在应用于指向对象的普通指针时产生指向对象一样.

这些规则可以合并.考虑你倒数第二个例子,**foo:

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

您可以根据需要添加任意数量的*s,结果始终相同.越*S,越多越好.

我们还可以考虑你的第五个例子&*foo:

  • 首先,foo隐式转换为指向自身的指针; 应用了一元*,foo再次屈服.
  • 然后,&应用于foo,产生指向foo该变量的指针.

&只能施加虽然给一个函数,而不是已被转换到一个函数指针(一个功能,除非,当然,函数指针是一个变量,在这种情况下,结果是一个指针到一个-指针- to-a-function;例如,你可以添加到你的列表中void (**pp_foo)() = &p7_foo;).

这就是为什么&&foo不起作用: &foo不是一个功能; 它是一个函数指针,它是一个右值.但是,它&*&*&*&*&*&*foo会起作用,&******&foo因为在这两个表达式中,&它总是应用于函数而不是rvalue函数指针.

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

  • 请不要编辑我的示例的语法.我非常专门地选择了这些示例来演示该语言的功能. (25认同)
  • 我不同意._*`越多,_less merry_越多. (12认同)
  • 作为旁注,C标准明确指出`&*`的组合相互抵消(6.5.3.2):`"一元&运算符产生其操作数的地址."`/ - /`"If操作数是一元*运算符的结果,运算符和&运算符都没有被计算,结果就好像都被省略了,除了对运算符的约束仍然适用,结果不是左值."`. (6认同)
  • @Jimmy:那些不是函数指针的引用,它们只是函数指针.`&foo`获取`foo`的地址,这会导致函数指针指向`foo`,正如人们所期望的那样. (2认同)
  • 我已经用更正确(而且更长)的解释更新了答案。可以说,C 和 C++ 中的函数指针很奇怪。 (2认同)
  • 你也不能为对象链接`&`运算符:给定`int p;`,`&p`产生一个指向`p`的指针并且是一个rvalue表达式; `&`运算符需要左值表达式. (2认同)
  • (在[“什么是右值、左值、x值、左值和纯右值?”](http://stackoverflow.com/questions/3601602/what-)的答案中对左值和右值有很多很好的解释。 are-rvalues-lvalues-xvalues-glvalues-and-prvalues)该问题涉及 C++0x 功能,但答案也很好地解释了右值和左值之间的差异。)。 (2认同)

mad*_*lao 6

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

从计算机的角度来看,函数只是一个存储器地址,如果执行,则执行其他指令.因此,C中的函数本身被建模为地址,这可能导致函数与其指向的地址"相同"的设计.