Generic programming in C

collinglass picture collinglass · Jan 20, 2014 · Viewed 8.9k times · Source

I am writing a generic linked list implementation in pure C.

struct Node {
    void *value;
    struct Node *next;
};

struct LinkedList {
    struct Node *start;
    struct Node *end;
};

void LinkedList_new(struct LinkedList* llist) {
    llist->start = 0;
    llist->end = 0;
    return;
}

void addNode( struct LinkedList *ll, void *_value ) {
    if ( NULL == ll->start ) {
        ll->start = (struct Node *) malloc( sizeof(struct Node) );
        ll->end = ll->start;
    } else {
        ll->end->next = (struct Node *) malloc( sizeof(struct Node) );
        ll->end = ll->end->next;
    }
    ll->end->value = _value;
    return;
};

This all works great. My problem is when I get to printing value to the screen. I can't seem to find a generic implementation for printing.

Is there a way to determine the TYPE allocated to void *? (And then just do conversion using a switch statement)

void printFunc(int aInt) {
    char str[15];
    sprintf(str, "%d", aInt);
    printf(str);
}

This is an implementation that works for int. Worst case I was thinking was writing a different function for each TYPE. Is this really my only route when using void *?

Is there a better way to do this?

Answer

unwind picture unwind · Jan 20, 2014

No, there's no way to figure that out from the pointer alone. That would require type information to be stored at some well-defined location in all run-time structures, which is simply not how C uses the machine.

The common solution is for the user of the datatype to provide the print function that the application needs, since the application will know the type of data being stored. That is, there is usually an iteration function that takes a function pointer, calling the user's function (which might print the element) on each element of the list.

Here's how such a function could look:

void LinkedList_foreach(const LinkedList *start,
                        bool (*func)(void *element, void *data), void *data);

The above should call func() for each element of the list, passing it the element's data and the additional user-supplied data pointer which can be used by the caller to maintain state for the traversal. The callback func() should return false to stop the iteration, true to keep going.

To print an integer, assuming the integers are stored in the pointers, you could have:

static bool print_int(void *element, void *data)
{
  printf("%d\n", (int) element);
  return true;
}

Also, please don't cast the return value of malloc() in C.