C generic inheritance with low verbosity - c

Having:
struct packet_sample_t {
int common_id;
int some;
char data[];
float foo;
}
Having the following function:
void dispatch_packet(void *packet);
My goal would be to parse the packet id and then call its handler, but I can't retrieve the struct variable common_id from void *.
I would like to create something like an interface in hight level languages, assuming that all my packets structures should have the variable common_id.
So I'm looking something that would work like below:
struct packet_base {
int common_id;
}
void dispatch_packet(void *packet) {
int common_id = ( (packet_base *)packet )->common_id;
switch(common_id) {...}
}
void test() {
packet_sample_t packet = {.common_id = 10, ...};
dispatch_packet((void *) &packet); //this function should retrieve `common_id`
packet_other_t other = {.common_id = 1};
dispatch_packet((void *) &other); // again with another packet
}
Im not that familiar to C language and I dont really know how I could do this. But in simple words, I would like to be able to cast a packet to its packet_base, that are sharing both a common variable.
EDIT: more details in the example

Your technique is valid. There's a number of ways to do struct inheritance in C, and this is one of them. 21st Century C might be a good read for you as well as Object-Oriented Programming with ANSI C.
You have a problems with how you're declaring and using your structs and types. Let's look at this.
struct packet_base {
int common_id;
};
This has the type struct packet_base. If you want to declare a pointer to this type you need to write struct packet_base *packet. If you want to cast a variable of this type it's (struct packet_base *)thing.
This is annoying, so you typically declare a type alias to the struct using typedef. The syntax is typedef <type> <alias>
typedef struct {
int common_id;
} packet_base_t;
That says the type struct { int common_id; } is aliased to packet_base_t. Now you can use packet_base_t as the type. packet_base_t *packet declares a pointer and (packet_base_t *)thing casts.
With that fixed, plus some small errors, it works. See What is the difference between char array vs char pointer in C? for char *data vs char data[].
typedef struct {
int common_id;
int some;
char *data;
float foo;
} packet_sample_t;
typedef struct {
int common_id;
} packet_base_t;
void dispatch_packet(void *arg) {
// It's simpler to cast to a new variable once then to muck
// up the code with casts.
packet_base_t *packet = (packet_base_t *)arg;
int common_id = packet->common_id;
printf("id: %d\n", common_id);
}

You can use union to aggregate the data of different types in a single structure
struct packet1_t
{
// Packet1 specific data
......
}
struct packet2_t
{
// Packet2 specific data
......
}
struct packet_t
{
int common_id;
union
{
struct packet1_t packet1;
struct packet2_t packet2;
......
}
} packet;
Now, based on the ID you can pick the correct type from the union:
int do_something_with_packet(packet_t packet)
{
switch (packet.common_id)
{
case 1:
do_something_with_packet1(packet.packet1);
break;
case 2:
do_something_with_packet2(packet.packet2);
break;
..................
}
....
}

Related

C function pointer and struct

I am new to C function pointer and structure. Here is what I want to achieve say there is a structure
typedef struct gfcrequest_t gfcrequest_t;
Later on this struct will be used to point to a function and the function will be called
gfcrequest_t *gfc_create();
gfr = gfc_create();
gfc_set_server(&gfr, server);
gfc_set_port(&gfr, port);
So are the following codes correct to initiate and later on I could add elements like server name and port number?
gfcrequest_t *gfc_create() {
struct out {
struct hostent *server;
int portno;
};
return out;
}
void gfc_set_port(gfcrequest_t **gfr, unsigned short port) {
gfr.portno = port;
}
void gfc_set_server(gfcrequest_t **gfr, const char *server) {
gfr.server = gethostbyname(server);
}
thats not how you do pointers to function.
to declare a pointer to function you do this:
if your function is:
int ft_somefink (int a, int b);
the pointer should be:
struct s_structure;
typedef struct s_structure t_structure;
struct s_structure
{
int (*funct)(int, int);
};
the typedef is there to simplify syntax.
its just an alias to avoid having to type "struct" everytime you use the structure.
you initialize it like so:
int main ()
{
t_structure name;
name.funct = &ft_somefink;
}
And call it like so:
int main()
{
t_structure name;
int a;
int b;
a = 1;
b = 2;
name.funct = &ft_somefink;
...
name.funct(a, b);
}
or like so if you pass the structure as pointer, it should look like this:
the main:
int main ()
{
t_structure *name;
...
function_somthing_useful(&name);
}
and the function:
void function_something_useful(t_structure **name)
{
if (!(*name = malloc(sizeof(t_structure))))
{
fprintf(stderr, "malloc error, not enough memory or swap nvm\n")
return ;
}
name->funct = &ft_somefink;
}
And, obviously, you call it then by:
name->funct(a, b);
note that you can malloc in main, doesnt matter. the idea to pass just the pointer is to avoid having to copy the whole structure everytime you pass it to a function.
the difference between . and -> operator is a dereferencing, but that would be another subject.
also i think it is better to pass the function as a pointer, instead of the whole thing because that might imply copying all of the functions instructions. not 100% sure of that tho... or rather depends on the system.
on linux reads are suposed to be "atomic", which, in my experience includes what happens on the stack. couldnt speak about other systems tho...
definitely could use someone to fill in the blanks here...

Using a function from a function array stored in a struct in C

I declared a struct like this one :
typedef struct s_data {
char buff[2048];
int len;
void *func[10];
struct data *next;
} t_data;
In my code, when passing a *data, I assigned some functions (just giving one so it is more understandable)
void init_data(t_data *data)
{
data->len = 0;
data->func[0] = &myfirstfunctions;
//doing the same for 9 others
}
My first function would be something taking as argument *data, and an int.
Then, I try to use this function in another function, doing
data->func[0](data, var);
I tried this and a couple of other syntaxes involving trying to adress (*func[0]) but none of them work. I kind of understood from other much more complex questions over there that I shouldn't store my function like this, or should cast it in another typedef, but I did not really understand everything as I am kind of new in programming.
void* can only be used reliably as a generic object pointer ("pointer to variables"). Not as a generic function pointer.
You can however convert between different function pointer types safely, as long as you only call the actual function with the correct type. So it is possible to do just use any function pointer type as the generic one, like this:
void (*func[10])(void);
...
func[0] = ((void)(*)(void))&myfirstfunction;
...
((whatever)func[0]) (arguments); // call the function
As you might note, the function pointer syntax in C is horrible. So I'd recommend using typedefs:
typedef void genfunc_t (void);
typedef int somefunc_t (whatever*); // assuming this is the type of myfirstfunction
Then the code turns far easier to read and write:
genfunc_t* func [10];
...
func[0] = (genfunc_t*)&myfirstfunction;
...
((somefunc_t*)func[0]) (arguments);
If all of your functions will have the same signature, you can do this like:
#include <stdio.h>
typedef void (*func)(void *, int);
struct s_data {
char buff[2048];
int len;
func f[10];
struct s_data *next;
};
static void
my_first_function(void *d, int x)
{
(void)d;
printf("%d\n", x + 2);
}
static void
init_data(struct s_data *data)
{
data->len = 1;
data->f[0] = my_first_function;
}
int
main(void)
{
struct s_data d;
init_data(&d);
d.f[0](NULL, 5);
return 0;
}
If your functions have different signatures, you will want to either use a union, or perhaps you will need several different members of the struct to store the function pointers.
The problem is that you haven't actually declared an array of function pointers. What you actually did is an array of pointers to void.
The syntax of declaring a pointer to function is as following:
function_return_type (*pointer_name)(arg1_type,arg2_type,...);
Then you can create an array of pointers to functions:
function_return_type (*arr_name[])(arg1_type, arg2_type,...)
Therefore, the declaration of your structure should look like this:
typedef void (*pointer_to_function)(void *, int);
struct s_data {
char buff[2048];
int len;
pointer_to_function array_of_pointeters[10];
struct s_data *next;
};
Good luck:)

Is it possible to create a function ( in C ), that can operate with different structure?

i'm looking for creating a function in C language that allows me to receive different structures type as parameters.
For example, if I create 3 different structures
struct a{
struct datatype0{
char test1[10];
}datatype;
struct a *next;
};
struct b{
struct datatype1{
int test1;
char test2[20];
int test3;
}datatype;
struct b *next;
};
struct c{
struct datatype2{
char test1;
char test2;
float test3;
int test4;
int test5;
}datatype;
struct c *next;
};
I wanna create a function that can receives one of theese three different struct as parameter, so I can call only it for initialize first, or second or third kind of structure:
void function("---")//<-- inside the brackets i need to insert a parameter that can be struct a, or struct b or struct c.
{
//here for example I can insert the initialize function that have to work with any struct.
}
I tryed to use a union, but I saw that I have to recreate the initializing function for each kind of struct...I tryed to use void pointers, but i need to cast theese inside the function and I need to create initializing function for each kind of struct too...
Any ideas??
The long and short of it is: avoid to do this whenever possible, but know that you Can pass different structs to a single function if you really have to.
Probably the easiest way is to create a wrapper struct, that contains 2 members: a union, and a flag to let you know which struct is passed.
typedef enum {
A,
B,
C
} struct_type;
struct _wrapper {
union {
struct a A;
struct b B;
struct c C;
};
struct_type flag;
};
void my_function(struct _wrapper *data)
{
switch (data->flag)
{
case A:
struct a val = data.A;
//do stuff with A
break;
case B:
struct b val = data.B;
break;
case C:
struct c val = data.C;
//...
break;
}
}
Another option, although it's considered bad practice, and is something you'll end up regretting is to rely on the fact that the offset of the first member of any struct is guaranteed to be 0. You can cast a pointer to any struct to a pointer to its first member. If the first member of all structs is compatible, you can rely on that (at your own risk).
One way of exploiting this is to set a function pointer as first member, or an enum field that you can use as a flag to identify the struct:
struct a {
void (*common_member)();//
/** other members **/
};
struct b {
void (*common_member)();//needn't be the same name though
/** other members **/
};
Then:
void my_func(void *data)
{//void pointer
((void (*)(void *))data)(data);//cast void *data to function pointer, and pass itself as an argument
}
This can work, if the structs are properly initialized, and the members point to the correct functions, but that's too many if's to rely on really.
Using the enum as first member is slightly less risky, but still not to be recommended. It's a sort of a combination of the function pointer and union approach
void my_func(void *data)
{
//cast void * to struct_type *, dereference AFTER the cast
//because you can't dereference a void *
switch(*((struct_type *) data))
{
case A: /* stuff */ break;
case B: /* struct b */ break;
}
}
All in all, use the first approach. Do not use the function pointer members, and acknowledge the third approach for what it is: true, you don't need a wrapper struct, but it's not that much safer than the original approach (function pointers), and no less verbose than the first approach (with union).
Bottom line: structs and unions are the way to go
In part it works. But for example, if I wanna create a function like:
typedef union elemento{
struct a A;
struct b B;
struct c C;
}elemento;
void inserimentoOrdinato(elemento dausare){
struct b prova;
prova.datatype.test1 = 3;
strcpy(prova.datatype.test2,"TESTA");
prova.datatype.test3 = 200;
prova.next = (struct a*)malloc(sizeof(struct a));
dausare.B = prova;
}
I need to use "dausare.B" or "dausare.C" for the different kinds of structures. It doesn't know itseflt which part of union has to use. Am I rigth? Thank you!
The answer is generic programming and function pointer:
**void * can be a pointer to any struct
Declaration part:
typedef void *Initializer(void* obj);//since every struct has its own fields to initialize
void function(void * obj, Initializer init)
{
init(obj);
}
Usage:
void InitA(void* a_void)
{
struct a* a = (struct a*) a_void;
//init a feilds
a->next = NULL;
}
void InitB(void* b_void)
{
struct b* b = (struct b*) b_void;
//init b feilds
b->next = NULL;
}
void InitC(void* c_void)
{
struct c* c = (struct c*) c_void;
//init a feilds
c->next = NULL;
}
int main()
{
struct a a;
struct b b;
struct c c;
Init(&a,InitA);
Init(&b,InitB);
Init(&c, initC);
return 0;
}
***Keep in mind that you dont have to build a different function for each struct if they have the same fields to initialize.

Having type A with N fields is it possible to merge it into new object of type B with N+x fields?

Say we have an instance of
struct Message {
char * topic;
int topicLength;
void * data;
int dataLength;
};
and we want to recreate it as an object of other type
struct CoreMessage {
int messaageId;
char * topic;
int topicLength;
void * data;
int dataLength;
char * senderId;
int senderIdLength;
};
Can we safly turn Message A into CoreMessage B? thing in C without copying contents, having types partly overlaping as shown here?
You can fake this with anonymous structures/unions. Anonymous structures have admittedly only been standardized since C11 but many popular compilers have supported them as an extension for ages.
That is something along these, admittedly-less-than-pretty, lines:
struct Message {
char * topic;
int topicLength;
void * data;
int dataLength;
char * senderId;
int senderIdLength;
};
struct CoreMessage {
int messageId;
union {
struct Message;
struct Message message;
};
};
No, you cannot do what you ask. You could come close, however, if you were willing to change the layout of struct CoreMessage like so:
struct CoreMessage {
struct Message message;
int messaageId;
char * senderId;
int senderIdLength;
};
Note that struct CoreMessage then contains an actual struct Message as a member (as opposed to a pointer to one). Then, given ...
struct CoreMessage cm;
struct CoreMessage *cmp = &cm;
struct Message *mp = &cm.message;
... you have (void *) cmp == (void *) mp, which can be useful for some of the kinds of things you might want to do. This is also adjusts automatically to changes to struct Message.
Alternatively, you can do something like this:
struct Message {
char * topic;
int topicLength;
void * data;
int dataLength;
maximum_alignment_requirement_t resv1;
char resv2[AS_MANY_BYTES_AS_ANY_MESSAGE_TYPE_MAY_NEED_INCLUDING_PADDING];
};
struct CoreMessage {
char * topic;
int topicLength;
void * data;
int dataLength;
maximum_alignment_requirement_t resv1;
int messaageId;
char * senderId;
int senderIdLength;
};
struct Message msg;
struct CoreMessage *cmp = (struct CoreMessage *) &msg;
That has a high probability of working as you would hope (and some system interfaces work pretty much this way) but C does not guarantee that those corresponding elements will be laid out the same way in the two different struct types.
Note, too, that it was no accident that I moved CoreMessage.messageId after the members corresponding to those of struct Message. It is much harder to arrange for corresponding layout if you do not do this, and the pointer value equivalence of the first alternative depends on it.
Not sure what you mean by "safely turn", but I would expect the answer to be "no". The structures are different, of course the smaller one can't magically be expected to expand into memory it didn't previously use.
There is no concept of "overlapping types" in C.
You can of course declare CoreMessage in terms of Message, but it won't help for the reverse transform from the smaller to the larger type except by making the transfer of the shared information easier:
struct CoreMessage {
int messageId;
struct Message message;
char *senderId;
int senderIdLength;
};
Now if we have:
struct Message a = { ... }; /* fully initialized */
struct CoreMessage b; /* we want to convert Message into this */
we can do:
b.messageId = 4711;
b.message = a; /* Copy all Message data over. */
b.senderId = "foo";
b.senderIdLength = 3;
Nothing is automatic here though, you have to do it yourself.
I'm not sure exactly what you mean by "turn into". I'm not sure how you can get casting to do this for you.
But, the C standard allows the compiler to put unused space between fields of a struct so, in general nothing would really work. You could make "CoreMessage" contain a "Message" and produce your result with a single assignment.

Changing a variable though a pointer to a structure pointer

I am trying to change a int variable through a structure that constant a pointer to other structure which one field is that variable.
I get one warning and one error in the compilation. Anyone can explain why and how can I do his using this code?
The code is:
typedef struct
{
struct TEEC_Session *ptr_struct;
} Context_model;
typedef struct
{ int t_S;
} Session_model;
void Attribution(Context_model* context,Session_model* session )
{
(*context).ptr_struct = session;
}
void change_t_S(Context_model* context )
{
(*(*context).ptr_struct).t_S = 5; // I Want to change t_S to 5 using only the
context structure
}
main()
{
Context_model context;
Session_model session;
Attribution(&context,&session);
// Now I want to change t_S using the context
change_t_S(&context);
}
modify the definition of Context_model as
typedef struct
{
Session_model *ptr_struct;
} Context_model;
and move it below the definition of Session_model.
struct TEEC_Session not defined in your code.
You are declaring your ptr_struct as having struct TEEC_Session * type, but then attempting to use it as a pointer of Session_model * type. That's an obvious type mismatch. That just doesn't make sense.
What is struct TEEC_Session? There's no other mention of TEEC_Session in your entire program. Why did you declare your ptr_struct field as a pointer to some completely random off-the-wall type struct TEEC_Session, and then completely forget about the existence of that struct TEEC_Session?
If your struct TEEC_Session type was supposed to be synonymous with Session_model type, you should have to told the compiler about that. For example, you could've declared Session_model as
typedef struct TEEC_Session
{
int t_S;
} Session_model;
and everything would work as intended.
Alternatively, you can get rid of any references to TEEC_Session entirely by reordering your declarations
typedef struct
{
int t_S;
} Session_model;
typedef struct
{
Session_model *ptr_struct;
} Context_model;
Finally, you are using C99-style comments in your code (//). C99 does not allow declaring functions without explicit return type. main() should be int main().
I show the code with additional declaration and the pointer dereferencing idiom.
This compiles ok in C, HTH.
struct TEEC_Session;
typedef struct
{ struct TEEC_Session *ptr_struct;
} Context_model;
typedef struct TEEC_Session
{ int t_S;
} Session_model;
void Attribution(Context_model* context,Session_model* session )
{
context->ptr_struct = session;
}
void change_t_S(Context_model* context )
{
context->ptr_struct->t_S = 5; // I Want to change t_S to 5 using only the context structure
}
int main_change_var(int argc, char **argv)
{
Context_model context;
Session_model session;
Attribution(&context,&session);
// Now I want to change t_S using the context
change_t_S(&context);
return 0;
}

Resources