为何结构体成员可声明为接收自身结构体指针的函数指针?
结构体中函数指针成员的常见问题解答
问题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
相关产品推荐
相关产品推荐

