Det går rätt bra att skriva det förhållandevis likt OOP-språk med fristående enheter, vars publika funktioner opererar på kontext i form av structar, där ett specifikt enhets publika funktioner får ett lämpligt prefix för att undvika kollision, som t.ex:
/* my_unit.h */
typedef struct MyUnit_ {
int some_value;
} MyUnit;
int my_unit_do_something(const MyUnit *context);
...
/* my_unit.c */
static int private_function(int value);
int my_unit_do_something(const MyUnit *context) {
return private_function(context->value);
}
static int private_function(int value) {
return (int)(value * 3.1415f);
}
Vill du dölja din structdefinition går det bra om du använder dynamisk minnesallokering, ex.
/* my_unit.h */
typedef struct MyUnit_ MyUnit;
MyUnit *my_unit_create();
void my_unit_destroy(MyUnit *self);
...
/* my_unit.c */
struct MyUnit_ {
char *data;
ssize_t data_size;
};
MyUnit * my_unit_create() {
MyUnit *self = calloc(1, sizeof(MyUnit));
self->data_size = 24;
self->data = calloc(self->data_size, sizeof(MyUnit));
return self;
}
void my_unit_destroy(MyUnit *self) {
free(self->data);
free(self);
}
En nackdel med C är att det är omständligt (en del boilerplatekod) att sätta upp structar med virtuella funktioner/funktionspekare vilket göra att det inte är lika vanligt, vilket i sin tur leder till att det är svårt att mocka bort objekt i test etc. Å andra sidan är det enkelt att hålla koll på vad som händer (med reservation för typkonverteringar) eftersom man måste skriva allt explicit. Att skriva C i C är dock ett rimligt råd, dvs låtsas inte att det är något annat språk. Du kan göra delar av det ex. C++ gör med klasshierarki etc manuellt men det riskerar att bli mycket jobb om du vill få ut något av det, undrar du hur mycket kan du ju alltid kolla på GObject.
I slutändan är väl det viktigaste att du har koll på vad som finns var om det är småprojekt, om någon annan ska behöva se det är det ju trevligt om det har högre läsbarhet en t.ex detta.