tags:

views:

149

answers:

3

I have some C structures related to a 'list' data structure. They look like this.

struct nmlist_element_s {
    void *data;
    struct nmlist_element_s *next;
};
typedef struct nmlist_element_s nmlist_element;

struct nmlist_s {
    void (*destructor)(void *data);
    int (*cmp)(const void *e1, const void *e2);
    unsigned int size;
    nmlist_element *head;
    nmlist_element *tail;
};
typedef struct nmlist_s nmlist;

This way I can have different data types being hold in "nmlist_element->data" . The "constructor" (in terms of OOP) has the following signature:

nmlist *nmlist_alloc(void (*destructor)(void *data));

Where "destructor" is specific function that de-allocated "data" (being hold by the nmlist_element).

If I want to have a list containing integers as data, my "destructor" would like this:

void int_destructor(void *data)
{
    free((int*)data);
}

Still i find it rather "unfriendly" for me to write a destructor functions for every simple primitive data type. So is there a trick to write something like this ? (for primitives):

void "x"_destructor(void *data, "x")
{
    free(("x" *)data);
}

PS: I am not a macro fan myself, and in my short experience regarding C, i don't use them, unless necessary.

+10  A: 

The C free() function is already generic. Just use free(data).

Kosta
+4  A: 

You shouldn't need to cast it to an int * to free it. You can just free the void * directly.

If you really want to do it with macros (or for future reference if you really do have a function that is not generic, unlike free()), the the best way is to use X macros.

#define TYPES_TO_DESTRUCT \
 X(int) \
 X(char) \
 X(t_mytype)

#define X(type) \
void type##_destructor(void *data) { free((type *)data); }

TYPES_TO_DESTRUCT

#undef X
Vicky
Dude you combobulated it!
bobobobo
A: 

I think Kosta's got it right. But you're asking for something like

#define DESTROY(x,data) (free((x##*)data))

bobobobo
This would would only simplify the _implementation_ of a destructor, but would still require a function to be written.
sbi
Your brackets are wrong there - you'd need#define DESTROY(x,data) (free((x##*)data))
Vicky
@sbi - no it doesn't, you'd just call DESTROY(int, data) instead of free(data). No implementation needed. It's entirely pointless though of course given that free takes a void * to start with.
Vicky
@Vicky - ty, bracketing fixed
bobobobo
@Vicky: Look again at nomemory's code. That code is taking the _address_ of a destructor. You can't take the address of a macro.
sbi
@sbi: Oh, I see what you mean. I silently assumed that nomemory would just remove the void (*destructor)(void *data); element from the nmlist_s struct definition. In that case, if you really must do it that way, X-macros are the way forward. I've edited my answer above to give an example.
Vicky