这不是结构内的函数,而是结构内的函数指针。
void (*addCount)();
定义addCount
为指向函数的指针。该函数返回void
并接受未指定数量的参数。
这就是空括号的含义。这是一个老式的非原型函数声明。很少有充分的理由使用非原型函数声明或定义。如果要指定函数不带参数,请使用(void)
而不是()
.
student.addCount = student_addCount;
该函数student_addCount
接受一个struct student
参数,但它的类型仍然与指针成员的类型兼容。像这样分配它实际上会禁用对呼叫的检查。这就是为什么旧式函数声明是一个坏主意的原因。
student.addCount();
这是通过函数指针的间接调用。由于函数指针类型没有指定需要多少参数,所以调用是合法的。由于被调用的实际函数需要一个 type 参数struct student
,因此行为是未定义的。使用旧式函数声明,完全由程序员自己决定是否正确使用参数;编译器不会帮助你。
由于您得到的结果似乎是有效的,因此您期望传递的参数很可能恰好位于内存中的正确位置,可能位于堆栈顶部。该函数被调用,并且相当合理地假设您已经传递了一个正确的参数值。它在内存或寄存器中查找该参数,然后找到 ... something。
这是您的程序没有未定义行为的版本:
#include <stdio.h>
struct student{
short count;
void (*addCount)(struct student a);
};
void student_addCount(struct student a){
a.count++;
}
int main(void){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount(student);
student.addCount(student);
student.addCount(student);
student.addCount(student);
student.addCount(student);
printf("%d\n",student.count);
}
输出是0
-- 因为count
被递增的是参数的一个成员,它是一个本地对象。
这是您可能想要的版本。它传递一个指向结构的指针,因此count
原始对象的成员struct student
由函数递增。输出是5
。
#include <stdio.h>
struct student{
short count;
void (*addCount)(struct student *a);
};
void student_addCount(struct student *a){
a->count++;
}
int main(void){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
printf("%d\n",student.count);
}