Don't use typedef void* for abstract datatypes.

By using "void*" for your "opaque pointers", you lose all typechecking, since void* is compatible with almost everything in C, and because typedef doesn't create a new type in C or C++, just a new name for an old type.

Instead, use forward declared structs...

/* Declare foo opaque type */ 
struct foo; 
foo* foo_create (void); 
void foo_manipulate (foo* f); 
void foo_delete (foo* f); 

/* Declare bar opaque type */ 
struct bar; 
bar* bar_create (void); 
void bar_do_it (bar* b); 
void bar_delete (bar* b); 

/* use them */ 
foo* f = foo_create (); /* ok */ 
bar* b = foo_create (); /* error */ 
foo_manipulate (f); /* ok */ 
bar_do_it (f); /* error */ 
foo_delete (f); /* ok */ 
bar_delete (f); /* error */ 
If you use struct forwards, all the errors will be caught by the compiler, if you use typedef void* the will not be caught.

To other minor style issues with the code in the story: If you make your constructor return the object, you can use it directly when declaring variables of the type:

foo* f = foo_create (); 
instead of

foo* f; 
f_create(&f); 
The library user save a line, and we avoid having a point in the code where "f" is uninititalized.

Also, it is a bad idea to hide the fact that it is a pointer with a typedef. This is because the type has pointer semantics, hiding the pointer can make it easier to assume value semantics by accident.

If the abstract datatype is implemented in C++, all the accessor functions (foo_create, foo_manipulate, foo_delete) should obviously be declared extern "C" for use in C code.

<abraham@dina.kvl.dk>