为什么结构内部的函数可以使用 C 语言
Why function inside an struct works C language
如这个小脚本所示。
#include <stdio.h>
struct student{
short count;
void (*addCount)();
};
void student_addCount(struct student a){
a.count++;
}
int main(){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount();
student.addCount();
student.addCount();
student.addCount();
student.addCount();
printf("%d\n",student.count);
}
我在结构中添加了一个指向函数的指针,但我不知道为什么会这样,因为函数 'addCount' 没有接收任何参数,它实际上累加了指定的次数。
我在 ideone.com、wandbox.org 和 WSL 中的编译器等不同环境中使用 GCC 6.3.0 编译此代码。
这是它与ideone一起工作的证明。
https://ideone.com/Cam4xY
这不是结构内部的函数,它是结构内部的函数指针。
void (*addCount)();
将 addCount
定义为指向函数的指针。函数 returns void
并采用未指定数量的参数。
这就是空括号的意思。那是一个 old-style non-prototype 函数声明。很少(如果有的话)有充分的理由使用 non-prototype 函数声明或定义。如果要指定函数不带参数,请使用 (void)
而不是 ()
.
student.addCount = student_addCount;
函数student_addCount
接受一个struct student
参数,但它的类型仍然与您的指针成员的类型兼容。像这样分配它实际上会禁用对调用的检查。这就是为什么 old-style 函数声明不是一个好主意。
student.addCount();
这是通过函数指针的间接调用。由于函数指针类型没有指定预期的参数数量,因此调用是合法的。由于被调用的实际函数需要一个 struct student
类型的参数,因此行为未定义。使用 old-style 函数声明,完全取决于程序员您来获得正确的参数;编译器不会帮助你。
由于您得到的结果似乎是有效的,您希望传递的参数很可能恰好位于内存中的正确位置,也许在堆栈的顶部。该函数被调用,它非常合理地假设您已经传递了一个正确的参数值。它在内存或寄存器中查找该参数,并找到... 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
是参数的成员,它是一个局部对象。
这是一个可以满足您的需求的版本。它传递一个指向结构的指针,因此原始 struct student
对象的 count
成员由该函数递增。输出为 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);
}
如这个小脚本所示。
#include <stdio.h>
struct student{
short count;
void (*addCount)();
};
void student_addCount(struct student a){
a.count++;
}
int main(){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount();
student.addCount();
student.addCount();
student.addCount();
student.addCount();
printf("%d\n",student.count);
}
我在结构中添加了一个指向函数的指针,但我不知道为什么会这样,因为函数 'addCount' 没有接收任何参数,它实际上累加了指定的次数。
我在 ideone.com、wandbox.org 和 WSL 中的编译器等不同环境中使用 GCC 6.3.0 编译此代码。
这是它与ideone一起工作的证明。 https://ideone.com/Cam4xY
这不是结构内部的函数,它是结构内部的函数指针。
void (*addCount)();
将 addCount
定义为指向函数的指针。函数 returns void
并采用未指定数量的参数。
这就是空括号的意思。那是一个 old-style non-prototype 函数声明。很少(如果有的话)有充分的理由使用 non-prototype 函数声明或定义。如果要指定函数不带参数,请使用 (void)
而不是 ()
.
student.addCount = student_addCount;
函数student_addCount
接受一个struct student
参数,但它的类型仍然与您的指针成员的类型兼容。像这样分配它实际上会禁用对调用的检查。这就是为什么 old-style 函数声明不是一个好主意。
student.addCount();
这是通过函数指针的间接调用。由于函数指针类型没有指定预期的参数数量,因此调用是合法的。由于被调用的实际函数需要一个 struct student
类型的参数,因此行为未定义。使用 old-style 函数声明,完全取决于程序员您来获得正确的参数;编译器不会帮助你。
由于您得到的结果似乎是有效的,您希望传递的参数很可能恰好位于内存中的正确位置,也许在堆栈的顶部。该函数被调用,它非常合理地假设您已经传递了一个正确的参数值。它在内存或寄存器中查找该参数,并找到... 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
是参数的成员,它是一个局部对象。
这是一个可以满足您的需求的版本。它传递一个指向结构的指针,因此原始 struct student
对象的 count
成员由该函数递增。输出为 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);
}