当声明为结构体字段内的字段时, void (func)(void) 和 void (*func)(void) 之间的区别?

Eri*_*mba 3 c

所以我被告知这些几乎彼此相同

void function1 (void(func)(int), int arg){
    func(arg);
}

void function2 (void(*func)(int), int arg){
    func(arg);
}
Run Code Online (Sandbox Code Playgroud)

当我执行这个时,它不会抛出任何错误。

void print_plus_1(int p)
{
    printf("p=%d\n", p+1);
}

void print_plus_2(int p)
{
    printf("p=%d\n", p+2);
}


int main(void)
{
    function1(print_plus_1, 1);
    function2(print_plus_2, 1);

}
Run Code Online (Sandbox Code Playgroud)

但是,当我在结构内初始化相同的 void (func) (int) 与 void (*func) (int) 模式时

struct foo
{
    void (func1)(int);
    void (*func2)(int);
};


void print_plus_1(int p)
{
    printf("p=%d\n", p+1);
}

void print_plus_2(int p)
{
    printf("p=%d\n", p+2);
}

int main(void)
{
    struct foo f;
    f.func1 = print_plus_1;
    f.func2 = print_plus_2;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它会抛出编译器错误吗?

error: field 'func1' declared as a function
    void (func1)(int);
Run Code Online (Sandbox Code Playgroud)

为什么 void (func)(void) 当写为回调函数而不是作为结构体内部的字段时可以工作?

Eri*_*hil 5

名义上,void (func)(int)声明一个接受 anint且不返回任何内容的函数,并void (*func)(int)声明一个指向该函数的指针。

\n

在标准 C 语言中,函数不是对象。它们不能分配给变量、作为参数传递或存储在结构成员中。

\n

然而,C 2018 6.7.6.3 8 说:

\n
\n

将参数声明为 \xe2\x80\x9c 返回类型\xe2\x80\x9d 的函数应调整为 \xe2\x80\x9c 指向返回类型\xe2\x80\x9d 的函数的指针,如 6.3.2.1 中所示。

\n
\n

这意味着,当您将参数声明为函数时,它会自动更改为将参数声明为函数指针。C 标准中没有任何内容规定在声明结构成员时进行此调整。这就是为什么您可以名义上(但实际上不是)将函数参数声明为函数,但不能将结构成员声明为函数。

\n