-4

如这个小脚本所示。

#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

4

1 回答 1

5

这不是结构内的函数,而是结构内的函数指针。

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);
}
于 2018-03-02T02:48:11.047 回答