How to create a universal library function in C?

Viewed 162

I want to manage various entities with the same "universal" functions. The entities are schematically declared as:

typedef struct {
  prefix_t pfx;
  int  i1;
  int  i2;
  int  i3;
} entity_t;

i.e. a typedef'd struct prefix for housekeeping (containing chaining pointers, flags, etc.) and a payload. There is one such type declaration per entity type.

The housekeeping functions need only to get a pointer to the prefix, which is easy, and a function which will "explore" the payload to return a meaningful quantity for the housekeeping.

With the example of binary tree management:

void TreeInsert (prefix_t *a, prefix_t *b, int (*compare) (prefix_t *, prefix_t *));

And inside the procedure, I have a call like this:

if (0 > compare(a, b)) {
   // a comes before b
} else {
  // a is the same as b or comes after
};

That's fine. The library function compiles without error nor warning.

But it is obvious that the compare function can't only reference the prefix. It needs to probe the payload to be useful:

int comp_entity (entity_t *a, entity_t *b) {
   return a->i1 - b->i1;
}

The compiler gives warning for comp_entity on the following line:

TreeInsert (&a->pfx, &b->pfx, comp_entity);

Since the library function is used for many different "entities", the compare function cannot be typecast at time of call. The arguments to the compare function cannot be typed for the prefix otherwise there is no means to access the payload.

Should I define a specific function type only for the purpose of passing the compare to the library function? Something like:

typedef int (func_cast *) (prefix_t *, prefix_t*);

and

TreeInsert (&a->pfx, &b->pfx, (func_cast)comp_entity);

I'd rather avoid this. Is this possible?

Nota:

I have found create universal function pointer to any type C language and How do I quiet the C compiler about a function pointer takes any number of arguments?, but they don't provide a solution.

1 Answers

Your compare function knows what the true type should be, so you would declare the arguments with type prefix_t * and cast the arguments inside of the function:

int comp_entity (prefix_t *a, prefix_t *b) {
   entity_t *ea = (entity_t *)a;
   entity_t *eb = (entity_t *)b;
   return ea->i1 - eb->i1;
}
Related