I am trying to create some c modules that has functions to internal functions without using c++, that I can then update and add features to while keeping things relatively clean and modular coding wise.
Let's say for example I have a simple math module that i'd like to continue to add functions to.
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);
};
with this setup if I continue to add functions to the struct ops; this will keep the size of my original math struct the same and can also maintain binary compatibility and things like that. I don't plan on having multiple implementation of these functions.
so with this simple setup, how can I init these functions? Currently I am doing something like this which seems a bit tedious, is there a nicer way to get it done. Maybe a language like c++ hides all this but I am looking for best practices without using c++ as I would like to know what's really going on.
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));
would the malloc of both structs be put in some init function in math.h or something like that? I am not sure, I've been looking for examples of code that does this but either I don't know where to look because I just can't find any.
The answer to your literal question is: provide a “constructor” function to initialize the struct
(s), ie, instead of allocating struct math
themselves, the user of your module would do something like:
struct math *math = newMath();
The function would do the necessary setup before returning the allocated struct
to the user.
However, I don't think your approach makes any sense. Your functions do not take either the containing struct math
or struct ops
as argument, so they should be just regular functions (ie, just put int sub(int *a, int*b);
in the header directly and the user of your module can call sub(&i, &j)
). And if you wish to make “private” functions, make them static
and do not introduce them in the header.
Or if you wish to simulate a C++-style class with struct
s, make the first argument of each function a pointer to the related struct math
(of course the function should then make use of the state of the struct
for this to make sense). You still don't need function pointers for this, though.
Having function pointers in the struct
would only be useful different struct math
instances in the same program need to have a different implementation for, say, sub
, and those instances would need to be interchangeable. That is, if math1->ops->sub
and math2->ops->sub
would point to a different function, and somewhere in the code you would need to call an unknown someMath->ops->sub
without knowing which type it is, then it might be justified to have the pointers. In all other scenarios you should ditch struct ops
.
You're not really trying to make a class, but a module. Your id
isn't actually in use anywhere. This sort of thing is done from time to time in C, but it's not a very common pattern. It also inhibits a lot of possible optimizations but here it is:
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
};
and then called with
int x = 2;
int y = 1;
math_ops.add(&x, &y);
If you want to expose the minimum amount in a header ( recommended ), you can separate it as follows:
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
};
If you can use C99 then I'd recommend instead defining math_ops
as
struct math_ops_tag math_ops = {
.add = add_impl,
.sub = sub_impl
};
to avoid mispositioning anything
Don't use struct
s for grouping functions to make things modular. Use symbol prefixes (C's poor man's namespaces) to group functions.
(Unless your goal is runtime polymorphism like C++
s virtual methods. Then your on the right track-- m_ops
is your vtable
, and like C++
's vtables
, you should initialize it statically, ie: without malloc
)
It seems like you're sort of trying to emulate C++ while "knowing what's really going on"..
What's really going on in C++'s classes is that although C++ speaks of "member" functions, there's no functions pointers and function tables involved at all, unless your class has virtual functions.
At the object file level C++ methods are just free-standing functions made out of methods by adding an implicit instance pointer argument, prefixing the method name with the class's name and mangling the result.
Also, don't pass ints by pointers. Pass them by values. int
s tend to take less or as much space as pointers. Passing ints by pointers makes things less efficient because you pass more data and have worse (or no) locality.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.