c结构和函数指针

时间:2015-07-11 16:49:19

标签: c pointers struct function-pointers

我试图在不使用c ++的情况下创建一些具有内部函数功能的c模块,然后我可以更新和添加功能,同时保持相对干净和模块化编码。

比方说,我有一个简单的数学模块,我想继续添加函数。

math.h中

struct math;
struct ops;

struct math
{
    int id;
    struct ops* m_ops;
};

struct ops
{
    int (* add)(int* a, int* b);
    int (* sub)(int* a, int* b);    
};

如果我继续向struct ops添加函数,请使用此设置;这将保持我的原始数学结构的大小相同,也可以保持二进制兼容性和类似的东西。我不打算多次实现这些功能。

所以通过这个简单的设置,我该如何启动这些功能?目前我正在做这样的事情似乎有点单调乏味,有没有更好的方法来完成它。也许像c ++这样的语言隐藏了这一切,但我正在寻找不使用c ++的最佳实践,因为我想知道它到底发生了什么。

int add(int *a, int*b)
{
    return ((*a) + (*b));
}

int sub(int *a, int*b)
{
    return ((*a) - (*b));
}

的main.c

    struct test* t_test = (struct test*)malloc(sizeof(struct test));
    math->id = 3;
    math->m_ops = (struct m_ops*)malloc(sizeof(struct m_ops));
    math->m_ops->add = &add;
    math->m_ops->sub = ⊂

    int a = 10;
    int b = 20;
    printf("adding: %d\n",math->m_ops->add(&a, &b));

将两个结构的malloc放入math.h中的某个init函数或类似的东西吗?我不确定,我一直在寻找能够做到这一点的代码示例,但要么我不知道在哪里看,因为我找不到任何代码。

3 个答案:

答案 0 :(得分:2)

你的文字问题的答案是:提供一个“构造函数”函数来初始化struct(s),即,而不是自己分配struct math,你的模块的用户会做类似的事情:

 struct math *math = newMath();

在将分配的struct返回给用户之前,该函数将进行必要的设置。

但是,我不认为你的方法有任何意义。您的函数不会将包含struct mathstruct ops作为参数,因此它们应该只是常规函数(即,只需将int sub(int *a, int*b);直接放入标题中,模块的用户就可以致电sub(&i, &j))。如果您希望制作“私人”功能,请将它们设为static,不要在标题中引入它们。

或者,如果您希望使用struct来模拟C ++样式的类,请使每个函数的第一个参数成为指向相关struct math的指针(当然函数应该使用这个struct的状态是有意义的。不过,你仍然不需要函数指针。

struct中使用函数指针只会有用,同一程序中的不同struct math个实例需要有不同的实现,比如sub那些实例需要可以互换。也就是说,如果math1->ops->submath2->ops->sub指向不同的函数,并且代码中的某个位置需要调用未知someMath->ops->sub而不知道它是哪种类型,那么它可能是有理由有指针。在所有其他情况下,您应该放弃struct ops

答案 1 :(得分:2)

你不是真的试图创建一个类,而是一个模块。您的id实际上并未在任何地方使用。这种事情在C中不时完成,但这不是一个非常常见的模式。它也抑制了许多可能的优化,但它是:

static int add_impl(int *a, int *b) {
    return *a + *b;
}

static int sub_impl(int *a, int *b) {
    return *a + *b;
}

static struct {
    int (*add)(int*, int*); // pointer to the add function
    int (*sub)(int*, int*);
} math_ops = {
    add_impl, // .add = add_impl
    sub_impl
};

然后用

调用
int x = 2;
int y = 1;
math_ops.add(&x, &y);

如果您想在标题中公开最低金额(推荐),您可以按如下方式将其分开:

mymath.h

struct math_ops_tag {
    int (*add)(int*, int*);
    int (*sub)(int*, int*);
};

extern struct math_ops_tag math_ops;

mymath.c

#include "mymath.h"

static int add_impl(int *a, int *b) {
    return *a + *b;
}

static int sub_impl(int *a, int *b) {
    return *a + *b;
}

struct math_ops_tag math_ops = {
    add_impl,
    sub_impl
};

如果您可以使用C99,我建议您将math_ops定义为

struct math_ops_tag math_ops = {
    .add = add_impl,
    .sub = sub_impl
};

避免错位任何事情

答案 2 :(得分:0)

不要将struct用于分组功能以使模块化。 使用符号前缀(C的穷人名称空间)来对函数进行分组。

(除非您的目标是C++虚拟方法之类的运行时多态性。然后您走在正确的轨道上 - m_ops就是您的vtable,就像C++一样vtables,您应该静态初始化它,即:没有malloc

看起来你有点想要模仿C ++而“知道真正发生了什么”..

C ++课程中真正发生的事情是,尽管C ++讲的是“成员”函数,但除非你的类具有虚函数,否则根本不涉及函数指针和函数表。

在目标文件级别,C ++方法只是通过添加隐式实例指针参数而由方法构成的独立函数, 在方法名前加上类的名称并对结果进行修改。

另外,不要通过指针传递int。按值传递它们。 int倾向于占用更少或更多的空间。通过指针传递int会降低效率,因为您传递的数据更多,而且地点更差(或没有)。