You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何结构体成员可声明为接收自身结构体指针的函数指针?

结构体中函数指针成员的常见问题解答

问题1:结构体test_t中的void (*exec)(struct test_t*);为何能正常工作?

这是函数指针成员的声明,并非“转换为自身结构体指针”。C语言允许在结构体内部使用自身的不完全类型(即尚未完成完整定义的结构体类型)来声明指针相关成员:

  • 当你写struct test_t时,编译器只需知道该类型存在即可,不需要立刻掌握它的完整大小或成员细节;
  • void (*exec)(struct test_t*);的含义是:exec是一个函数指针,它指向的函数接收一个struct test_t*类型的参数,返回值为void。
    等结构体的}结束后,struct test_t就成为完全类型,后续的typedef只是给它起了别名test_t,不影响之前声明的有效性。

问题2:switch-case中的test.exec = fcn1; test.exec(&test);逻辑如何确立?

这段代码的逻辑在编译和运行阶段分别处理:

  • 编译阶段:编译器明确test是test_t类型变量,exec是该类型的函数指针成员;fcn1的签名(void(test_t*))与exec的类型完全匹配,因此赋值操作合法;调用test.exec(&test)时,编译器能识别&test是test_t*类型,符合函数指针的参数要求。
  • 运行阶段:根据用户输入的test.num,程序会给exec赋值不同的函数地址,随后通过函数指针调用对应函数,传入当前test变量的地址,实现对test数据的修改。

问题3:是否是将函数赋值给结构体成员?结构体未编译完成时如何识别自身类型?

本质是把函数的地址赋值给结构体的函数指针成员(函数名本身就是函数的地址)。关于结构体未完成定义时的类型识别:

  • 在结构体内部声明时,struct test_t是不完全类型,但C语言允许用不完全类型声明指针(包括函数参数中的指针)——因为指针的大小是固定的,编译器不需要知道结构体的完整大小就能处理该声明;
  • 当结构体的}结束后,struct test_t就成为完全类型,后续的typedef只是为它创建别名test_t,不影响之前的声明。

问题4:(*x)(struct y*)这类语法的用途是什么?

这是函数指针的标准声明语法,拆解后含义:

  • (*x)表示x是一个指针;
  • (struct y*)表示这个指针指向的函数接收一个struct y*类型的参数;
  • 前面的返回值类型(比如你的代码里的void)表示函数的返回值类型。

这类语法的核心用途:

  • 实现回调机制:允许在运行时动态切换要执行的函数;
  • 模拟面向对象中的“成员函数”:把数据(结构体的成员)和操作数据的函数绑定在一起,让代码更模块化。

代码示例

typedef struct test_t{
    int num;
    void (*exec)(struct test_t*);
}test_t;

void fcn0(test_t* test);
void fcn1(test_t* test);
void fcn2(test_t* test);

int main(){
    while(1){
        test_t test = {
            .num = 0,
            .exec = fcn0
        };

        printf("Enter a number: ");
        scanf("%d", &test.num);

        switch (test.num)
        {
        case 1:
            test.exec = fcn1;
            test.exec(&test);
            break;
        case 2:
            test.exec = fcn2;
            test.exec(&test);
            break;
        
        default:
            test.exec = fcn0;
            test.exec(&test);
            break;
        }

        printf("Value: %d\n", test.num);
    }
}

void fcn0(test_t* test){
    printf("Entered fcn0\n");
    test->num = 0;
}

void fcn1(test_t* test){
    printf("Entered fcn1\n");
    test->num = 1;
}

void fcn2(test_t* test){
    printf("Entered fcn2\n");
    test->num = 2;
}

内容的提问来源于stack exchange,提问作者verpas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:20:17