这样做有几个方面,使所有这些运算符组合可以相同的方式工作。
所有这些工作的根本原因是一个函数(如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)();有再次因为函数到函数指针转换的结果相同。
&foo接受的地址foo,这导致函数指针指向foo,正如人们所期望的那样。