为什么`(*)`可以从函数参数列表中的函数指针中省略?

Kam*_*Cuk 15 c

用gcc8编译:

#include <stdio.h>
void some_func(void f1(void), void (*f2)(void))
{
    printf("%d\n", f1);
    printf("%d\n", f2);
}
Run Code Online (Sandbox Code Playgroud)

给(仅)以下警告:

<source>:11:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'void (*)(void)' [-Wformat=]
     printf("%d\n", f1);
<source>:12:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'void (*)(void)' [-Wformat=]
     printf("%d\n", f2);
Run Code Online (Sandbox Code Playgroud)

为什么类型f1相同f2?仅f2被声明为函数指针.我希望f1不会编译,因为它命名一个函数类型,而不是函数指针.什么规则说,函数参数列表中的函数类型更改为指向该函数类型的指针?

PSk*_*cik 21

因为标准(6.7.6.3p8)说明了这一点

参数声明为''函数返回类型''应调整为''指向函数返回类型'的指针,如6.3.2.1所述.

它类似于数组参数如何调整为指针(6.7.63.p7),如果你考虑它.

void some_func(void (void));
void some_func(void (*)(void));
Run Code Online (Sandbox Code Playgroud)

是兼容的声明,就像:

void other_func(char string[]);
void other_func(char *string);
Run Code Online (Sandbox Code Playgroud)

是.


需要注意的是,调整不会使void some_func(void (*)(void)兼容void some_other_func(void (**)(void)void yet_another_func(void (*****)(void)那至于功能方面,声明并不真正反映使用了,(尽管是语言的原始作者的意图).在标准化的C中,​​由于函数标识符如何衰减到指针,并且由于无论使用函数类型还是函数指针类型进行调用无关紧要,您可以任意调用任意函数*:

#include <stdio.h>
int main()
{
    (*puts)("hello world");
    (******puts)("hello world");
    (***&*&*puts)("hello world"); //& cancels a * as per 6.5.3.2p3

    int (*p)(char const*) = puts;
    int (**pp)(char const*) = &p;
    int (***ppp)(char const*) = &pp;

    (**ppp)("hello world"); //at least two asterisks required here
}
Run Code Online (Sandbox Code Playgroud)