Well, you can still design nice abstract data types in C. You start by typedef
ing a struct, providing create/destroy functions, and then other setters/getters/doers to operate on that struct:
typedef struct {
/* maintain private state here */
unsigned int x;
char *y;
} mytype_t;
/** Creates a new mytype... */
mytype_t *mytype_create(unsigned int x, char *y);
/** Destroys a mytype, freeing all associated memory. */
void mytype_destroy(mytype_t *t);
/** Does something to mytype... */
void mytype_do_something(mytype_t *t, int bla);
So you implement these functions and maintain your state by accessing the 'private' members in the struct, whose pointer is passed in to each function.
Then you would use this interface like this:
mytype_t* t = mytype_create(foo, bar);
mytype_do_something(t);
/* do some other stuff */
mytype_destroy(t);
The important point is this: as soon as you typedef a struct, users of the type are not allowed to access its members. They should only talk to it via the public interface/functions defined for it.
I see people typedefing structs just to avoid having to type 'struct' all over the place, but you have to think of it as defining a new abstract type, whose internal implementation may change. Sure a user of the type can dive in and access the members but that's a bad thing to do . A typedef struct means "private, keep out!". This is basic information hiding.
I tend to use a prefix style of naming too, i.e. mytype_verb
. This helps with intellisense because I can type mytype_
and get a list of functions for that type. It also helps with naming conflicts since there is no namespace support in C, which is why you will see most C libraries use prefixes (like sqlite3_
) in front of everything they define.