为什么结构中的函数适用于C语言

时间:2018-03-02 02:34:15

标签: c struct function-pointers gcc6

如这个小脚本所示。

#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);
}

我在结构中添加了指向函数的指针,但我不知道为什么它可以作为函数&#39; addCount&#39;没有收到任何参数,它实际上累计了指定的次数。

我正在使用GCC 6.3.0在不同的环境中编译此代码,例如ideone.com,wandbox.org和WSL中的编译器。

这里证明它与ideone一起使用。 https://ideone.com/Cam4xY

1 个答案:

答案 0 :(得分:5)

这不是结构中的函数,它是结构中的函数指针。

void (*addCount)();

addCount定义为指向函数的指针。该函数返回void并获取未指定数量的参数。

这就是空括号的含义。那是一种旧式的非原型函数声明。如果有的话,很少有理由使用非原型函数声明或定义。如果要指定函数不带参数,请使用(void)而不是()

student.addCount = student_addCount;

函数student_addCount采用struct student参数,但其类型仍与指针成员的类型兼容。像这样分配它基本上禁止检查呼叫。这就是旧式函数声明是个坏主意的原因。

student.addCount();

这是通过函数指针的间接调用。由于函数指针类型未指定预期的参数数量,因此调用是合法的。由于调用的实际函数需要类型为struct student的单个参数,因此行为未定义。对于旧式函数声明,程序员完全可以正确地得到正确的参数;编译器不会帮助你。

由于你得到的似乎是有效的结果,你希望传递的参数可能恰好位于内存中的正确位置,也许是在堆栈顶部。该函数被调用,并且它非常合理地假设您已经传递了适当的参数值。它在内存或寄存器中查找该参数,并查找... 某些内容

以下是没有未定义行为的程序版本:

#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);
}