我试图在不使用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函数或类似的东西吗?我不确定,我一直在寻找能够做到这一点的代码示例,但要么我不知道在哪里看,因为我找不到任何代码。
答案 0 :(得分:2)
你的文字问题的答案是:提供一个“构造函数”函数来初始化struct
(s),即,而不是自己分配struct math
,你的模块的用户会做类似的事情:
struct math *math = newMath();
在将分配的struct
返回给用户之前,该函数将进行必要的设置。
但是,我不认为你的方法有任何意义。您的函数不会将包含struct math
或struct ops
作为参数,因此它们应该只是常规函数(即,只需将int sub(int *a, int*b);
直接放入标题中,模块的用户就可以致电sub(&i, &j)
)。如果您希望制作“私人”功能,请将它们设为static
,不要在标题中引入它们。
或者,如果您希望使用struct
来模拟C ++样式的类,请使每个函数的第一个参数成为指向相关struct math
的指针(当然函数应该使用这个struct
的状态是有意义的。不过,你仍然不需要函数指针。
在struct
中使用函数指针只会有用,同一程序中的不同struct math
个实例需要有不同的实现,比如sub
,和那些实例需要可以互换。也就是说,如果math1->ops->sub
和math2->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会降低效率,因为您传递的数据更多,而且地点更差(或没有)。