C Casting between different struct-pointers during "simulated inheritance" - c

Hey I'm currently porting a C++ program into C and I simplified I'm using the following code when I'm simulating inheritence from C++ classes using structs in C.
typedef struct GenTask GenTask;
typedef struct Task Task;
typedef struct UserTask UserTask;
struct GenTask{
char name[MAXCHAR];
boolean isUserTask;
int k;
void (*print)(Task*);
};
GenTask* newGenTask(const char* n){
GenTask* inhTask = (GenTask*)malloc(sizeof(GenTask));
strncpy(inhTask->name, n, MAXCHAR);
inhTask->k = 1;
return inhTask;
}
struct Task{
GenTask* inhTask;
};
void printTask(Task* task){
printf("\nThis is Task: %s",task->inhTask->name);
}
Task* newTask(const char* n){
Task* task = (Task*)malloc(sizeof(Task));
task->inhTask = newGenTask(n);
task->inhTask->isUserTask = false;
task->inhTask->print = printTask;
return task;
}
void deleteTask(Task* task){
free(task->inhTask);
free(task);
}
struct UserTask{
GenTask* inhTask;
int m;
};
void printUserTask(Task* task){
UserTask* ut = (UserTask*)task;
printf("\nThis is UserTask nbr: %d",ut->m);
}
UserTask* newUserTask(const char* n){
UserTask *ut = (UserTask*)malloc(sizeof(UserTask));
ut->inhTask = newGenTask(n);
ut->inhTask->isUserTask = true;
ut->inhTask->print = printUserTask;
ut->m=100;
return ut;
}
void deleteUserTask(UserTask* utask){
free(utask->inhTask);
free(utask);
}
I've tried running the code and it works as expected (or rather as I wish for it to work;)). My question though, is if there is any risk that the extra "UserTask-memory" is exposed after type casting like below.
Task* task = (Task*)newUserTask("A UserTask");
There seems to be no problem when I cast back into a UserTask pointer.
UserTask* utask = (UserTask*)task;
I assume that when I free the memory for "A UserTask", I suffies to free utask and using deleteUserTask(utask)? If I instead free task using deleteTask(task), I guess the UserTask specific memory won't get freed.
I my all new to both C++ and C, been using Java before and the dynamic memory allocation is still a bit scary... Thanks for any help!
/Patrik

I think the 'normal' way to do this in C is to include the parent struct inline not as a pointer, i.e.:
struct Task{
GenTask inhTask;
};
That way a pointer to a task struct can be up cast to a Task*. And of course the 'parent' is freed automatically along with the child instance.

Related

static initialization of queue

I'm working on a high-reliance implementation of an algorithm for an embedded system.
in main.c:
//.. in main()
int queue_buffer[QUEUE_LEN + 1] = { 0 };
Queue queue;
queue_init(&queue, QUEUE_LEN, queue_buffer);
do_things_on_queue(&queue);
//.. in main()
in queue.c:
void queue_init(Queue *q, int len, int *data) {
q->head = 0;
q->tail = 0;
q->len = len;
q->data = data; // an array of length `len + 1`
}
in queue.h:
typedef struct queue {
int head;
int tail;
int len;
int *data;
} Queue;
I would like to 1. have main.c to not know about Queue; and 2. not use malloc for intializing queue_buffer_ but rather do it statically.
this implies that ideally main.c would be:
//.. in some function
Queue *queue = queue_init(something_eventually);
do_things_with_queue(queue);
//.. in some function
Is it possible to modify queue_init in queue.cto achieve this in C99? If so, what's the best approach?
Tentative Solutions
I am aware of the technique discussed in this post yet they seems unfeasible without using malloc. I know for sure that I will simultaneously have 4 queues at most. This makes me think that I could declare a memory pool for the queues as a static global array of queues of size 4. Is it ok to use global variables in this case?
#KamilKuk suggested to just have queue_init to return the structure itself since QUEUE_LEN is known at compile time. This requires the following:
in queue.c:
Queue queue_init(void) {
Queue q;
q.head = 0;
q.tail = 0;
q.len = QUEUE_LEN;
for (int i=0; i < QUEUE_LEN; i++)
q.data[i] = 0;
return q;
}
in queue.h:
typedef struct queue {
int head;
int tail;
int len;
int data[QUEUE_LEN];
} Queue;
Queue queue_init(void);
This appears to greatly simplify the structure initialization.
However this does not solve the privacy problem, since main.c should know about Queue to initialize this struct.
Thank you.
I would like to 1. have main.c to not know about Queue; and 2. not use
malloc for intializing queue_buffer_ but rather do it statically.
this implies that ideally main.c would be:
//.. in some function
Queue queue = queue_init(something_eventually);
do_things_with_queue(&queue);
//.. in some function
No, your objectives do not imply a solution as described. You cannot declare or use an object of type Queue anywhere that the definition of that type is not visible. That follows directly from the language's rules, but if you want a more meaningful justification then consider that even if main does not access any of the members of Queue, it still needs the definition simply to know how much space to reserve for one.
It's not obvious to me that it serves a useful purpose to make type Queue opaque in main.c (or anywhere), but if that's what you want then in that scope you can forward declare it, never define it, and work only with pointers to it:
typedef struct queue Queue;
// ...
Queue *queue = queue_init(something_eventually);
do_things_with_queue(queue);
For that to work without dynamic memory allocation, the pointed-to Queue objects must have static storage duration, but that does not mean that they need to be globals -- either in the sense of being accessible via a name with external linkage, or in the sense of being declared at file scope.
Additionally, you have the option of allocating the data arrays automatically, as in your example code, so as to not tie up that memory in queues when they are not in use. If you prefer, you can wrap that up in a macro or two for a bit of additional ease of use (left as an exercise).
For example,
queue.h
typedef struct queue Queue;
Queue *queue_init(int queue_size, int queue_data[]);
void queue_release(Queue *queue);
queue.c
#include "queue.h"
struct queue {
int head;
int tail;
int len;
int *data;
};
Queue *queue_init(int queue_len, int queue_data[]) {
// queue_pool has static storage duration and no linkage
static Queue queue_pool[4] = {{0}};
// Find an available Queue, judging by the data pointers
for (Queue *queue = queue_pool;
queue < queue_pool + sizeof(queue_pool) / sizeof(*queue_pool);
queue++) {
if (queue->data == NULL) {
// This one will do. Initialize it and return a pointer to it.
queue->head = 0;
queue->tail = 0;
queue->len = queue_len;
queue->data = queue_data;
return queue;
}
}
// no available Queue
return NULL;
}
void queue_release(Queue *queue) {
if (queue) {
queue->data = NULL;
}
}
main.c
// ... in some function
int queue_data[SOME_QUEUE_LENGTH];
Queue *queue = queue_init(SOME_QUEUE_LENGTH, queue_data);
do_things_with_queue(queue);
queue_release(queue);
// ...
Of course, if you prefer, you can put the queue data directly into the queue structure, as in your tentative solution, and maybe provide a flag there to indicate whether the queue is presently in use. That would relieve users of any need to provide storage, at the cost of tying up the storage for all the elements of all the queues for the whole duration of the program.
The best way to do this is to pass a buffer and its size to the init function, exactly as you already have.
It is a very bad idea to worry about calling a function versus having the data fixed at compile time. Both the execution time and code size for a tiny initialization like this is negligible. Making your code interface awkward just to save a few instructions at startup is not just a waste of effort, it makes the code hard to maintain and risks introducing bugs.
There are a number of embedded systems or libraries that provide a macro which declares both the storage array and the control structure in one go and gives them a name which is known only to the library, and then you have to use a macro to generate the name every time you access the item. For an example of this you might look at osMailQDef in CMSIS-OS. I don't really recommend this method though. It is too easy to get wrong, whereas doing it the usual way is easy to read and any reviewer will be able to spot a mistake straight away.
I would typically do:
// queue.h
#define QUEUE_INIT(data, len) { .len = len, .data = data }
#define QUEUE_INIT_ON_STACK(len) QUEUE_INIT((char[len]){0}, len)
// main.c
static Queue queue = QUEUE_INIT_ON_STACK(QUEUE_LEN + 1);
As for PIMPL idiom, it's easy to implement with descriptors just like file descriptors in LINUX, especially when the count is static.
// queue.h
typedef Queue int;
void do_things_with_queue(Queue);
// queue.c
struct RealQueue { stuff; };
static struct RealQeueue arr[4] = { stuff };
static struct RealQeueue *get_RealQueue(Queue i) {
assert(0 <= i && i < sizeof(arr)/sizeof(*arr));
return &arr[i];
}
void do_things_with_queue(Queue i) {
struct RealQueue *queue = get_RealQueue(i);
}
// main.c
static Queue queue = 1;
// etc.
Or you can break all hell and synchronize alignment between source and header file:
// queue.h
struct Queue {
// This has to be adjusted __for each compiler and environment__
alignas(60) char data[123];
};
#define QUEUE_INIT() { 0xAA, 0xBB, etc.. constant precomputed data }
// queue.c
struct RealQeueue { stuff; };
static_assert(alingof(struct RealQueue) == alignof(struct Queue), "");
static_assert(sizeof(struct RealQueue) == sizeof(struct Queue), "");
void do_things_with_queue(Queue *i) {
struct RealQueue *queue = (struct RealQueue*)i->data;
}

Attempting to lock a spinlock in the down function results in freezing

I am attempting to implement my own version of a semaphore into a linux vm and am running into a crash when I attempt to lock a spinlock inside the down function. Using GDB I found that the down is called immediately after the create function so the problem is definitely there.
Here is the create function:
asmlinkage long sys_create(int value, char name[32], char key[32]){
struct sem *new_sem = (struct sem*) kmalloc(sizeof(struct sem), GFP_ATOMIC);
struct sem_node *new_sem_node = (struct sem_node*) kmalloc(sizeof(struct sem_node), GFP_ATOMIC);
struct sem_node *curr_sem = sem_list_head;
new_sem_node->sem = new_sem;
spin_lock(&sem_lock);
new_sem->sem_id = IDcntr++;
spin_lock_init(&(new_sem->lock));
strncpy(new_sem->key, key, 32);
strncpy(new_sem->name, name, 32);
if(curr_sem == NULL)
{
sem_list_head = new_sem_node;
}
else
{
while(curr_sem->next != NULL)
{
curr_sem = curr_sem->next;
}
curr_sem->next = new_sem_node;
}
spin_unlock(&sem_lock);
return new_sem->sem_id;
}
Functions spin_lock, spin_unlock, and spin_lock_init are working as intended. The down function calls:
spin_lock(&(sem_list_head->sem->lock));
right at the beginning and freezes. To be more specific, in the gdb terminal, I try and get to the next line and it stops and in the actual machine it's completely stopped. No other functions are called between the create and down function. Below is the header file that defines the sem_node, process_node, and sem objects used in the create and down functions:
int IDcntr = 1;
DEFINE_SPINLOCK(sem_lock);
struct sem_node
{
struct sem* sem;
struct sem_node* next;
};
struct process_node
{
struct process_node* next;
struct task_struct* task;
};
struct sem
{
int value;
long sem_id;
spinlock_t lock;
char key[32];
char name[32];
struct process_node* head;
struct process_node* tail;
};
struct sem_node* sem_list_head = NULL;
Through independent testing the function DEFINE_SPINLOCK and object spinlock_t are working as intended. After thorough debugging the problem is in the create function. I freely admit that I am still learning how semaphores work so chances are I didn't set variables correctly or define things correctly. Any help in pointing me the right way would be greatly appreciated.

Static allocation of struct members within another static struct?

I am trying to implement a low-level thread lock without the use of dynamic memory allocation; this code will basically be used on a completely bare-bones kernel.
However, I am running into the problem of receiving a seg fault when I am trying to dereference a member inside this global static struct. My code is as such
My wrapper struct
/** LOCKING STRUCT & FUNCTIONS **/
struct lock {
int free;
struct thread_list* wait_list;
struct thread* current_holder;
};
The nested struct(intended as a linked list sort of deal)
struct thread_list {
struct thread *head;
};
And the member inside this list
struct thread {
void *top; // top of the stack for this thread
void *sp; // current stack pointer for this thread (context)
void (*start_func)(void *);
void *arg;
int state;
int exit_value;
struct thread *join_thread;
struct thread *next_thread;
int id;
};
The method I'm trying to implement is as such
void lock_init (struct lock *lk) {
lk->free = 1; //Set lock as free
struct thread_list waiting = lk->wait_list; //Get waitlist, works fine
waiting->head = NULL; //Set waitlist's head to null, SEGFAULTS HERE
}
I am not super proficient at C, but I can't seem to figure out the correct methodology/syntax to make my code work like this.
struct thread_list waiting = lk->wait_list; //Get waitlist, works fine
waiting->head = NULL; //Set waitlist's head to null, SEGFAULTS HERE
waiting is not a struct pointer but a struct variable . To access member using it you need to use . operator -
waiting.head = NULL;
Or to use -> operator declare it as a struct pointer .

Using Windows slim read/write lock

/*language C code*/
#include "windows.h"
typedef struct object_s
{
SRWLOCK lock;
int data;
} object_t, *object_p; /*own and pointer type*/
void thread(object_p x)
{
AcquireSRWLockExclusive(&x->lock);
//...do something that could probably change x->data value to 0
if(x->data==0)
free(x);
else
ReleaseSRWLockExclusive(&x->lock);
}
void main()
{
int i;
object_p object=(object_p)malloc(sizeof(object_t));
InitializeSRWLock(&object->lock);
for(i=0;i<3;i++)
CreateThread(0,0,thread,object,0);
}
As you can figure out in the codes above, what I have to accomplish is to let one thread conditionally free the object on which the other two may block. Codes above are obviously flawed because if object is set free along with the lock, all blocking threads give us nowhere but wrong.
A solution below
/*language C code*/
#include "windows.h"
typedef struct object_s
{
/*change: move lock to stack in main()*/
int data;
} object_t, *object_p; /*own and pointer type*/
void thread(void * x)
{
struct {
PSRWLOCK l;
object_p o;
} * _x=x;
AcquireSRWLockExclusive(_x->l);
//...do something that could probably change x->data value to 0
if(_x->o->data==0)
free(_x->o);
ReleaseSRWLockExclusive(&x->lock);
}
void main()
{
int i;
SRWLOCK lock; /*lock over here*/
object_p object=(object_p)malloc(sizeof(object_t));
InitializeSRWLock(&lock);
/*pack for thread context*/
struct
{
PSRWLOCK l;
object_p o;
} context={&lock, object};
for(i=0;i<3;i++)
CreateThread(0,0,thread,&context,0);
}
works in this case but not applicable however, in my final project because there is actually a dynamic linked list of objects. By applying this solution it means that there must be a list of locks accordingly, each lock for an object and moreover, when a certain object is set free, its lock must be set free at the same time. There is nothing new compared with the first code section.
Now I wonder if there is an alternative solution to this. Thank you very much!
The solution is to not allocate the lock together with the data. I would suggest that you move the data out of that struct and replace it with a pointer to the data. Your linked list can then free the data first, and then the node, without any problems. Here's some pseudo code:
typedef struct
{
lock_t lock;
int* data_ptr;
} something_t;
void init_something (something_t* thing, ...)
{
thing->lock = init_lock();
thing->data_ptr = malloc(...); // whatever the data is supposed to be
}
void free_something (somthing_t* thing)
{
lock(thing->lock);
free(thing->data_ptr);
thing->data_ptr = NULL;
unlock(thing->lock);
}
...
void linked_list_delete_node (...)
{
free_something(node_to_delete->thing);
free(node_to_delete);
}
...
void thread (void* x)
{
lock(x->lock);
//...do something that could probably change x->data_ptr->data... to 0
if(x->data_ptr->data == 0)
{
free_something(x->data_ptr->data);
}
unlock(x->lock);
}
AcquireSRWLockExclusive(lock);
if(_x->o->data==0)
free(_x);
ReleaseSRWLockExclusive(lock);
As a sidenote, a C program for Windows can never return void. A hosted C program must always return int. Your program will not compile on a C compiler.
Also, CreateThread() expects a function pointer to a function returning a 32-bit value and taking a void pointer as parameter. You pass a different kind of function pointer, function pointer casts aren't allowed in C, nor am I sure what sort of madness Windows will execute if it gets a different function pointer than what it expects. You invoke undefined behavior. This can cause your program to crash or behave in unexpected or random ways.
You need to change your thread function to DWORD WINAPI thread (LPVOID param);

Object-orientation in C

What would be a set of nifty preprocessor hacks (ANSI C89/ISO C90 compatible) which enable some kind of ugly (but usable) object-orientation in C?
I am familiar with a few different object-oriented languages, so please don't respond with answers like "Learn C++!". I have read "Object-Oriented Programming With ANSI C" (beware: PDF format) and several other interesting solutions, but I'm mostly interested in yours :-)!
See also Can you write object oriented code in C?
I would advise against preprocessor (ab)use to try and make C syntax more like that of another more object-oriented language. At the most basic level, you just use plain structs as objects and pass them around by pointers:
struct monkey
{
float age;
bool is_male;
int happiness;
};
void monkey_dance(struct monkey *monkey)
{
/* do a little dance */
}
To get things like inheritance and polymorphism, you have to work a little harder. You can do manual inheritance by having the first member of a structure be an instance of the superclass, and then you can cast around pointers to base and derived classes freely:
struct base
{
/* base class members */
};
struct derived
{
struct base super;
/* derived class members */
};
struct derived d;
struct base *base_ptr = (struct base *)&d; // upcast
struct derived *derived_ptr = (struct derived *)base_ptr; // downcast
To get polymorphism (i.e. virtual functions), you use function pointers, and optionally function pointer tables, also known as virtual tables or vtables:
struct base;
struct base_vtable
{
void (*dance)(struct base *);
void (*jump)(struct base *, int how_high);
};
struct base
{
struct base_vtable *vtable;
/* base members */
};
void base_dance(struct base *b)
{
b->vtable->dance(b);
}
void base_jump(struct base *b, int how_high)
{
b->vtable->jump(b, how_high);
}
struct derived1
{
struct base super;
/* derived1 members */
};
void derived1_dance(struct derived1 *d)
{
/* implementation of derived1's dance function */
}
void derived1_jump(struct derived1 *d, int how_high)
{
/* implementation of derived 1's jump function */
}
/* global vtable for derived1 */
struct base_vtable derived1_vtable =
{
&derived1_dance, /* you might get a warning here about incompatible pointer types */
&derived1_jump /* you can ignore it, or perform a cast to get rid of it */
};
void derived1_init(struct derived1 *d)
{
d->super.vtable = &derived1_vtable;
/* init base members d->super.foo */
/* init derived1 members d->foo */
}
struct derived2
{
struct base super;
/* derived2 members */
};
void derived2_dance(struct derived2 *d)
{
/* implementation of derived2's dance function */
}
void derived2_jump(struct derived2 *d, int how_high)
{
/* implementation of derived2's jump function */
}
struct base_vtable derived2_vtable =
{
&derived2_dance,
&derived2_jump
};
void derived2_init(struct derived2 *d)
{
d->super.vtable = &derived2_vtable;
/* init base members d->super.foo */
/* init derived1 members d->foo */
}
int main(void)
{
/* OK! We're done with our declarations, now we can finally do some
polymorphism in C */
struct derived1 d1;
derived1_init(&d1);
struct derived2 d2;
derived2_init(&d2);
struct base *b1_ptr = (struct base *)&d1;
struct base *b2_ptr = (struct base *)&d2;
base_dance(b1_ptr); /* calls derived1_dance */
base_dance(b2_ptr); /* calls derived2_dance */
base_jump(b1_ptr, 42); /* calls derived1_jump */
base_jump(b2_ptr, 42); /* calls derived2_jump */
return 0;
}
And that's how you do polymorphism in C. It ain't pretty, but it does the job. There are some sticky issues involving pointer casts between base and derived classes, which are safe as long as the base class is the first member of the derived class. Multiple inheritance is much harder - in that case, in order to case between base classes other than the first, you need to manually adjust your pointers based on the proper offsets, which is really tricky and error-prone.
Another (tricky) thing you can do is change the dynamic type of an object at runtime! You just reassign it a new vtable pointer. You can even selectively change some of the virtual functions while keeping others, creating new hybrid types. Just be careful to create a new vtable instead of modifying the global vtable, otherwise you'll accidentally affect all objects of a given type.
I once worked with a C library that was implemented in a way that struck me as quite elegant. They had written, in C, a way to define objects, then inherit from them so that they were as extensible as a C++ object. The basic idea was this:
Each object had its own file
Public functions and variables are defined in the .h file for an object
Private variables and functions were only located in the .c file
To "inherit" a new struct is created with the first member of the struct being the object to inherit from
Inheriting is difficult to describe, but basically it was this:
struct vehicle {
int power;
int weight;
}
Then in another file:
struct van {
struct vehicle base;
int cubic_size;
}
Then you could have a van created in memory, and being used by code that only knew about vehicles:
struct van my_van;
struct vehicle *something = &my_van;
vehicle_function( something );
It worked beautifully, and the .h files defined exactly what you should be able to do with each object.
C Object System (COS) sounds promising (it's still in alpha version). It tries to keep minimal the available concepts for the sake of simplicity and flexibility: uniform object oriented programming including open classes, metaclasses, property metaclasses, generics, multimethods, delegation, ownership, exceptions, contracts and closures. There is a draft paper (PDF) that describes it.
Exception in C is a C89 implementation of the TRY-CATCH-FINALLY found in other OO languages. It comes with a testsuite and some examples.
Both by Laurent Deniau, which is working a lot on OOP in C.
The GNOME desktop for Linux is written in object-oriented C, and it has an object model called "GObject" which supports properties, inheritance, polymorphism, as well as some other goodies like references, event handling (called "signals"), runtime typing, private data, etc.
It includes preprocessor hacks to do things like typecasting around in the class hierarchy, etc. Here's an example class I wrote for GNOME (things like gchar are typedefs):
Class Source
Class Header
Inside the GObject structure there's a GType integer which is used as a magic number for GLib's dynamic typing system (you can cast the entire struct to a "GType" to find it's type).
Slightly off-topic, but the original C++ compiler, Cfront, compiled C++ to C and then to assembler.
Preserved here.
If you think of methods called on objects as static methods that pass an implicit 'this' into the function it can make thinking OO in C easier.
For example:
String s = "hi";
System.out.println(s.length());
becomes:
string s = "hi";
printf(length(s)); // pass in s, as an implicit this
Or something like that.
I used to do this kind of thing in C, before I knew what OOP was.
Following is an example, which implements a data-buffer which grows on demand, given a minimum size, increment and maximum size. This particular implementation was "element" based, which is to say it was designed to allow a list-like collection of any C type, not just a variable length byte-buffer.
The idea is that the object is instantiated using the xxx_crt() and deleted using xxx_dlt(). Each of the "member" methods takes a specifically typed pointer to operate on.
I implemented a linked list, cyclic buffer, and a number of other things in this manner.
I must confess, I have never given any thought on how to implement inheritance with this approach. I imagine that some blend of that offered by Kieveli might be a good path.
dtb.c:
#include <limits.h>
#include <string.h>
#include <stdlib.h>
static void dtb_xlt(void *dst, const void *src, vint len, const byte *tbl);
DTABUF *dtb_crt(vint minsiz,vint incsiz,vint maxsiz) {
DTABUF *dbp;
if(!minsiz) { return NULL; }
if(!incsiz) { incsiz=minsiz; }
if(!maxsiz || maxsiz<minsiz) { maxsiz=minsiz; }
if(minsiz+incsiz>maxsiz) { incsiz=maxsiz-minsiz; }
if((dbp=(DTABUF*)malloc(sizeof(*dbp))) == NULL) { return NULL; }
memset(dbp,0,sizeof(*dbp));
dbp->min=minsiz;
dbp->inc=incsiz;
dbp->max=maxsiz;
dbp->siz=minsiz;
dbp->cur=0;
if((dbp->dta=(byte*)malloc((vuns)minsiz)) == NULL) { free(dbp); return NULL; }
return dbp;
}
DTABUF *dtb_dlt(DTABUF *dbp) {
if(dbp) {
free(dbp->dta);
free(dbp);
}
return NULL;
}
vint dtb_adddta(DTABUF *dbp,const byte *xlt256,const void *dtaptr,vint dtalen) {
if(!dbp) { errno=EINVAL; return -1; }
if(dtalen==-1) { dtalen=(vint)strlen((byte*)dtaptr); }
if((dbp->cur + dtalen) > dbp->siz) {
void *newdta;
vint newsiz;
if((dbp->siz+dbp->inc)>=(dbp->cur+dtalen)) { newsiz=dbp->siz+dbp->inc; }
else { newsiz=dbp->cur+dtalen; }
if(newsiz>dbp->max) { errno=ETRUNC; return -1; }
if((newdta=realloc(dbp->dta,(vuns)newsiz))==NULL) { return -1; }
dbp->dta=newdta; dbp->siz=newsiz;
}
if(dtalen) {
if(xlt256) { dtb_xlt(((byte*)dbp->dta+dbp->cur),dtaptr,dtalen,xlt256); }
else { memcpy(((byte*)dbp->dta+dbp->cur),dtaptr,(vuns)dtalen); }
dbp->cur+=dtalen;
}
return 0;
}
static void dtb_xlt(void *dst,const void *src,vint len,const byte *tbl) {
byte *sp,*dp;
for(sp=(byte*)src,dp=(byte*)dst; len; len--,sp++,dp++) { *dp=tbl[*sp]; }
}
vint dtb_addtxt(DTABUF *dbp,const byte *xlt256,const byte *format,...) {
byte textÝ501¨;
va_list ap;
vint len;
va_start(ap,format); len=sprintf_len(format,ap)-1; va_end(ap);
if(len<0 || len>=sizeof(text)) { sprintf_safe(text,sizeof(text),"STRTOOLNG: %s",format); len=(int)strlen(text); }
else { va_start(ap,format); vsprintf(text,format,ap); va_end(ap); }
return dtb_adddta(dbp,xlt256,text,len);
}
vint dtb_rmvdta(DTABUF *dbp,vint len) {
if(!dbp) { errno=EINVAL; return -1; }
if(len > dbp->cur) { len=dbp->cur; }
dbp->cur-=len;
return 0;
}
vint dtb_reset(DTABUF *dbp) {
if(!dbp) { errno=EINVAL; return -1; }
dbp->cur=0;
if(dbp->siz > dbp->min) {
byte *newdta;
if((newdta=(byte*)realloc(dbp->dta,(vuns)dbp->min))==NULL) {
free(dbp->dta); dbp->dta=null; dbp->siz=0;
return -1;
}
dbp->dta=newdta; dbp->siz=dbp->min;
}
return 0;
}
void *dtb_elmptr(DTABUF *dbp,vint elmidx,vint elmlen) {
if(!elmlen || (elmidx*elmlen)>=dbp->cur) { return NULL; }
return ((byte*)dbp->dta+(elmidx*elmlen));
}
dtb.h
typedef _Packed struct {
vint min; /* initial size */
vint inc; /* increment size */
vint max; /* maximum size */
vint siz; /* current size */
vint cur; /* current data length */
void *dta; /* data pointer */
} DTABUF;
#define dtb_dtaptr(mDBP) (mDBP->dta)
#define dtb_dtalen(mDBP) (mDBP->cur)
DTABUF *dtb_crt(vint minsiz,vint incsiz,vint maxsiz);
DTABUF *dtb_dlt(DTABUF *dbp);
vint dtb_adddta(DTABUF *dbp,const byte *xlt256,const void *dtaptr,vint dtalen);
vint dtb_addtxt(DTABUF *dbp,const byte *xlt256,const byte *format,...);
vint dtb_rmvdta(DTABUF *dbp,vint len);
vint dtb_reset(DTABUF *dbp);
void *dtb_elmptr(DTABUF *dbp,vint elmidx,vint elmlen);
PS: vint was simply a typedef of int - I used it to remind me that it's length was variable from platform to platform (for porting).
I think what Adam Rosenfield posted is the correct way of doing OOP in C. I'd like to add that what he shows is the implementation of the object. In other words the actual implementation would be put in the .c file, while the interface would be put in the header .h file. For example, using the monkey example above:
The interface would look like:
//monkey.h
struct _monkey;
typedef struct _monkey monkey;
//memory management
monkey * monkey_new();
int monkey_delete(monkey *thisobj);
//methods
void monkey_dance(monkey *thisobj);
You can see in the interface .h file you are only defining prototypes. You can then compile the implementation part " .c file" into a static or dynamic library. This creates encapsulation and also you can change the implementation at will. The user of your object needs to know almost nothing about the implementation of it. This also places focus on the overall design of the object.
It's my personal belief that oop is a way of conceptualizing your code structure and reusability and has really nothing to do with those other things that are added to c++ like overloading or templates. Yes those are very nice useful features but they are not representative of what object oriented programming really is.
ffmpeg (a toolkit for video processing) is written in straight C (and assembly language), but using an object-oriented style. It's full of structs with function pointers. There are a set of factory functions that initialize the structs with the appropriate "method" pointers.
If you really thinks catefully, even standard C library use OOP - consider FILE * as an example: fopen() initializes an FILE * object, and you use it use member methods fscanf(), fprintf(), fread(), fwrite() and others, and eventually finalize it with fclose().
You can also go with the pseudo-Objective-C way which is not difficult as well:
typedef void *Class;
typedef struct __class_Foo
{
Class isa;
int ivar;
} Foo;
typedef struct __meta_Foo
{
Foo *(*alloc)(void);
Foo *(*init)(Foo *self);
int (*ivar)(Foo *self);
void (*setIvar)(Foo *self);
} meta_Foo;
meta_Foo *class_Foo;
void __meta_Foo_init(void) __attribute__((constructor));
void __meta_Foo_init(void)
{
class_Foo = malloc(sizeof(meta_Foo));
if (class_Foo)
{
class_Foo = {__imp_Foo_alloc, __imp_Foo_init, __imp_Foo_ivar, __imp_Foo_setIvar};
}
}
Foo *__imp_Foo_alloc(void)
{
Foo *foo = malloc(sizeof(Foo));
if (foo)
{
memset(foo, 0, sizeof(Foo));
foo->isa = class_Foo;
}
return foo;
}
Foo *__imp_Foo_init(Foo *self)
{
if (self)
{
self->ivar = 42;
}
return self;
}
// ...
To use:
int main(void)
{
Foo *foo = (class_Foo->init)((class_Foo->alloc)());
printf("%d\n", (foo->isa->ivar)(foo)); // 42
foo->isa->setIvar(foo, 60);
printf("%d\n", (foo->isa->ivar)(foo)); // 60
free(foo);
}
This is what may be resulted from some Objective-C code like this, if a pretty-old Objective-C-to-C translator is used:
#interface Foo : NSObject
{
int ivar;
}
- (int)ivar;
- (void)setIvar:(int)ivar;
#end
#implementation Foo
- (id)init
{
if (self = [super init])
{
ivar = 42;
}
return self;
}
#end
int main(void)
{
Foo *foo = [[Foo alloc] init];
printf("%d\n", [foo ivar]);
[foo setIvar:60];
printf("%d\n", [foo ivar]);
[foo release];
}
My recommendation: keep it simple. One of the biggest issues I have is maintaining older software (sometimes over 10 years old). If the code is not simple, it can be difficult. Yes, one can write very useful OOP with polymorphism in C, but it can be difficult to read.
I prefer simple objects that encapsulate some well-defined functionality. A great example of this is GLIB2, for example a hash table:
GHastTable* my_hash = g_hash_table_new(g_str_hash, g_str_equal);
int size = g_hash_table_size(my_hash);
...
g_hash_table_remove(my_hash, some_key);
The keys are:
Simple architecture and design pattern
Achieves basic OOP encapsulation.
Easy to implement, read, understand, and maintain
I'm a bit late to the party here but I like to avoid both macro extremes - too many or too much obfuscates code, but a couple obvious macros can make the OOP code easier to develop and read:
/*
* OOP in C
*
* gcc -o oop oop.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct obj2d {
float x; // object center x
float y; // object center y
float (* area)(void *);
};
#define X(obj) (obj)->b1.x
#define Y(obj) (obj)->b1.y
#define AREA(obj) (obj)->b1.area(obj)
void *
_new_obj2d(int size, void * areafn)
{
struct obj2d * x = calloc(1, size);
x->area = areafn;
// obj2d constructor code ...
return x;
}
// --------------------------------------------------------
struct rectangle {
struct obj2d b1; // base class
float width;
float height;
float rotation;
};
#define WIDTH(obj) (obj)->width
#define HEIGHT(obj) (obj)->height
float rectangle_area(struct rectangle * self)
{
return self->width * self->height;
}
#define NEW_rectangle() _new_obj2d(sizeof(struct rectangle), rectangle_area)
// --------------------------------------------------------
struct triangle {
struct obj2d b1;
// deliberately unfinished to test error messages
};
#define NEW_triangle() _new_obj2d(sizeof(struct triangle), triangle_area)
// --------------------------------------------------------
struct circle {
struct obj2d b1;
float radius;
};
#define RADIUS(obj) (obj)->radius
float circle_area(struct circle * self)
{
return M_PI * self->radius * self->radius;
}
#define NEW_circle() _new_obj2d(sizeof(struct circle), circle_area)
// --------------------------------------------------------
#define NEW(objname) (struct objname *) NEW_##objname()
int
main(int ac, char * av[])
{
struct rectangle * obj1 = NEW(rectangle);
struct circle * obj2 = NEW(circle);
X(obj1) = 1;
Y(obj1) = 1;
// your decision as to which of these is clearer, but note above that
// macros also hide the fact that a member is in the base class
WIDTH(obj1) = 2;
obj1->height = 3;
printf("obj1 position (%f,%f) area %f\n", X(obj1), Y(obj1), AREA(obj1));
X(obj2) = 10;
Y(obj2) = 10;
RADIUS(obj2) = 1.5;
printf("obj2 position (%f,%f) area %f\n", X(obj2), Y(obj2), AREA(obj2));
// WIDTH(obj2) = 2; // error: struct circle has no member named width
// struct triangle * obj3 = NEW(triangle); // error: triangle_area undefined
}
I think this has a good balance, and the errors it generates (at least with default gcc 6.3 options) for some of the more likely mistakes are helpful instead of confusing. The whole point is to improve programmer productivity no?
#include "triangle.h"
#include "rectangle.h"
#include "polygon.h"
#include <stdio.h>
int main()
{
Triangle tr1= CTriangle->new();
Rectangle rc1= CRectangle->new();
tr1->width= rc1->width= 3.2;
tr1->height= rc1->height= 4.1;
CPolygon->printArea((Polygon)tr1);
printf("\n");
CPolygon->printArea((Polygon)rc1);
}
Output:
6.56
13.12
Here is a show of what is OO programming with C.
This is real, pure C, no preprocessor macros. We have inheritance,
polymorphism and data encapsulation (including data private to classes or objects).
There is no chance for protected qualifier equivalent, that is,
private data is private down the innheritance chain too.
But this is not an inconvenience because I don't think it is necessary.
CPolygon is not instantiated because we only use it to manipulate objects
of down the innheritance chain that have common aspects but different
implementation of them (Polymorphism).
If I were going to write OOP in C I would probably go with a pseudo-Pimpl design. Instead of passing pointers to structs, you end up passing pointers to pointers to structs. This makes the content opaque and facilitates polymorphism and inheritance.
The real problem with OOP in C is what happens when variables exit scope. There are no compiler-generated destructors and that can cause issues. Macros can possibly help, but it is always going to be ugly to look at.
I'm also working on this based on a macro solution. So it is for the bravest only, I guess ;-) But it is quite nice already, and I'm already working on a few projects on top of it.
It works so that you first define a separate header file for each class. Like this:
#define CLASS Point
#define BUILD_JSON
#define Point__define \
METHOD(Point,public,int,move_up,(int steps)) \
METHOD(Point,public,void,draw) \
\
VAR(read,int,x,JSON(json_int)) \
VAR(read,int,y,JSON(json_int)) \
To implement the class, you create a header file for it and a C file where you implement the methods:
METHOD(Point,public,void,draw)
{
printf("point at %d,%d\n", self->x, self->y);
}
In the header you created for the class, you include other headers you need and define types etc. related to the class. In both the class header and in the C file you include the class specification file (see the first code example) and an X-macro. These X-macros (1,2,3 etc.) will expand the code to the actual class structs and other declarations.
To inherit a class, #define SUPER supername and add supername__define \ as the first line in the class definition. Both must be there. There is also JSON support, signals, abstract classes, etc.
To create an object, just use W_NEW(classname, .x=1, .y=2,...). The initialization is based on struct initialization introduced in C11. It works nicely and everything not listed is set to zero.
To call a method, use W_CALL(o,method)(1,2,3). It looks like a higher order function call but it is just a macro. It expands to ((o)->klass->method(o,1,2,3)) which is a really nice hack.
See Documentation and the code itself.
Since the framework needs some boilerplate code, I wrote a Perl script (wobject) that does the job. If you use that, you can just write
class Point
public int move_up(int steps)
public void draw()
read int x
read int y
and it will create the class specification file, class header, and a C file, which includes Point_impl.c where you implement the class. It saves quite a lot of work, if you have many simple classes but still everything is in C. wobject is a very simple regular expression based scanner which is easy to adapt to specific needs, or to be rewritten from scratch.
Another way to program in an object oriented style with C is to use a code generator which transforms a domain specific language to C. As it's done with TypeScript and JavaScript to bring OOP to js.
I'd suggest you to try out COOP
It features Classes, Inheritance, Exceptions, Memory management, its own Unit Testing Framework for C, and more.
All of this while maintaining type safety and (many parts of the) intellisence!
And, yes, it uses Macro magics to do it.
#Adam Rosenfield has a very good explanation of how to achieve OOP with C
Besides, I would recommend you to read
1) pjsip
A very good C library for VoIP. You can learn how it achieves OOP though structs and function pointer tables
2) iOS Runtime
Learn how iOS Runtime powers Objective C. It achieves OOP through isa pointer, meta class
For me object orientation in C should have these features:
Encapsulation and data hiding (can be achieved using structs/opaque pointers)
Inheritance and support for polymorphism (single inheritance can be achieved using structs - make sure the abstract base is not instantiable)
Constructor and destructor functionality (not easy to achieve)
Type checking (at least for user-defined types as C doesn't enforce any)
Reference counting (or something to implement RAII)
Limited support for exception handling (setjmp and longjmp)
On top of the above it should rely on ANSI/ISO specifications and should not rely on compiler-specific functionality.
Look at http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. If nothing else reading through the documentation is an enlightening experience.
If you need to write a little code
try this: https://github.com/fulminati/class-framework
#include "class-framework.h"
CLASS (People) {
int age;
};
int main()
{
People *p = NEW (People);
p->age = 10;
printf("%d\n", p->age);
}
The open-source Dynace project does exactly that. It's at https://github.com/blakemcbride/Dynace
I have managed to implement inheritance and polymorphism in C.
I can do single inheritance with virtual tables and I can implement multiple interfaces with a technique where the struct that implements an interface simply creates the interface struct by giving it its own methods and a pointer to itself. The interface struct then calls these methods and, among other parameters, it passes them the pointer to the struct which created the implementation of the interface.
When it comes to inheriting non abstract classes, I have achieved that with virtual tables, I have already explained inheritance with virtual tables in this answer. The code from that answer doesn't allow implementation of multiple interfaces. In this answer however, I changed my code so that it allows implementation of multiple interfaces. Here is the entire code that I posted on github. I will post the code here as well but maybe it is more readable on github, as I put the code in multiple files.
Here is the code, I have structs Zivotinja, Pas, Automobil and the struct MozeProizvestiZvuk. This last struct is an interface. Pas and Automobil implement it. Struct Pas also inherits from Zivotinja.
Here is the code for the main function
Pas *pas = Pas_new_sve(4, 20, "some dog name");
MozeProizvestiZvuk *mozeProizvestiZvuk = pas->getMozeProizvestiZvuk(pas);
mozeProizvestiZvuk->proizvediZvuk(mozeProizvestiZvuk->strukturaKojuMetodeInterfejsaKoriste);
mozeProizvestiZvuk->proizvediZvuk(mozeProizvestiZvuk->strukturaKojuMetodeInterfejsaKoriste);
printf("number of times it made noise = %d\n", mozeProizvestiZvuk->getKolikoPutaJeProizveoZvuk(mozeProizvestiZvuk->strukturaKojuMetodeInterfejsaKoriste));
Automobil *automobil = Automobil_new("Sandero", 2009);
MozeProizvestiZvuk *zvukAutomobil = automobil->getMozeProizvestiZvuk(automobil);
for(int i=0; i<3; i++){
zvukAutomobil->proizvediZvuk(zvukAutomobil->strukturaKojuMetodeInterfejsaKoriste);
}
printf("number of times it made noise = %d\n", zvukAutomobil->getKolikoPutaJeProizveoZvuk(zvukAutomobil->strukturaKojuMetodeInterfejsaKoriste));
Zivotinja *zivotinja = Zivotinja_new(10);
zivotinja->vTable->ispisiPodatkeOZivotinji(zivotinja);
zivotinja->vTable->obrisi(&zivotinja);
Zivotinja *pasKaoZivotinja = Pas_new_sve(5, 50, "Milojko");
pasKaoZivotinja->vTable->ispisiPodatkeOZivotinji(pasKaoZivotinja);
int godine = pasKaoZivotinja->vTable->dajGodine(pasKaoZivotinja);
printf("age of the dog which was upcasted to an animal = %d \n", godine);
pasKaoZivotinja->vTable->obrisi(&pasKaoZivotinja);
Here is the MozeProizvestiZvuk.h file
#ifndef MOZE_PROIZVESTI_ZVUK_H
#define MOZE_PROIZVESTI_ZVUK_H
typedef struct MozeProizvestiZvukStruct{
void (*proizvediZvuk)(void *strukturaKojuMetodeInterfejsaKoriste);
unsigned int (*getKolikoPutaJeProizveoZvuk)(void *strukturaKojaImplementiraInterfejs);
void *strukturaKojuMetodeInterfejsaKoriste;
}MozeProizvestiZvuk;
#endif
Here is the Automobil struct which implements this interface.
#include"MozeProizvestiZvuk.h"
#include<stdlib.h>
typedef struct AutomobilStruct{
const char *naziv;
int godinaProizvodnje;
unsigned int kolikoPutaJeProizveoZvuk;
MozeProizvestiZvuk* (*getMozeProizvestiZvuk)(struct AutomobilStruct *_this);
}Automobil;
MozeProizvestiZvuk* Automobil_getMozeProizvestiZvuk(Automobil *automobil);
Automobil* Automobil_new(const char* naziv, int godiste){
Automobil *automobil = (Automobil*) malloc(sizeof(Automobil));
automobil->naziv = naziv;
automobil->godinaProizvodnje = godiste;
automobil->kolikoPutaJeProizveoZvuk = 0;
automobil->getMozeProizvestiZvuk = Automobil_getMozeProizvestiZvuk;
return automobil;
}
void Automobil_delete(Automobil **adresaAutomobilPointera){
free(*adresaAutomobilPointera);
*adresaAutomobilPointera = NULL;
}
unsigned int Automobil_getKolikoJeZvukovaProizveo(Automobil *automobil){
return automobil->kolikoPutaJeProizveoZvuk;
}
void Automobil_proizvediZvuk(Automobil *automobil){
printf("Automobil koji se zove %s, godiste %d proizvodi zvuk. \n", automobil->naziv, automobil->godinaProizvodnje);
automobil->kolikoPutaJeProizveoZvuk++;
}
MozeProizvestiZvuk* Automobil_getMozeProizvestiZvuk(Automobil *automobil){
MozeProizvestiZvuk *mozeProizvestiZvuk = (MozeProizvestiZvuk*) malloc(sizeof(MozeProizvestiZvuk));
mozeProizvestiZvuk->strukturaKojuMetodeInterfejsaKoriste = automobil;
mozeProizvestiZvuk->proizvediZvuk = Automobil_proizvediZvuk;
mozeProizvestiZvuk->getKolikoPutaJeProizveoZvuk = Automobil_getKolikoJeZvukovaProizveo;
return mozeProizvestiZvuk;
}
Here is the Zivotinja struct, this struct doesn't inherit from anything, neither does it implement any interfaces, but the struct Pas will inherit from Zivotinja.
#include<stdio.h>
#include<stdlib.h>
typedef struct ZivotinjaVTableStruct{
void (*ispisiPodatkeOZivotinji)(void *zivotinja);
int (*dajGodine) (void *zivotinja);
} ZivotinjaVTable;
typedef struct ZivotinjaStruct{
ZivotinjaVTable *vTable;
int godine;
} Zivotinja;
void ispisiPodatkeOOvojZivotinji(Zivotinja* zivotinja){
printf("Ova zivotinja ima %d godina. \n", zivotinja->godine);
}
int dajGodineOveZivotinje(Zivotinja *z){
return z->godine;
}
void Zivotinja_obrisi(Zivotinja **adresaPointeraKaZivotinji){
Zivotinja *zivotinjaZaBrisanje = *adresaPointeraKaZivotinji;
free(zivotinjaZaBrisanje);
*adresaPointeraKaZivotinji = NULL;
}
struct ZivotinjaVTableStruct zivotinjaVTableGlobal = {Zivotinja_obrisi, ispisiPodatkeOOvojZivotinji, dajGodineOveZivotinje};
Zivotinja* Zivotinja_new(int godine){
ZivotinjaVTable *vTable = &zivotinjaVTableGlobal;
Zivotinja *z = (Zivotinja*) malloc(sizeof(Zivotinja));
z->vTable = vTable;
z->godine = godine;
}
And finally, here is the struct Pas which inherits from Zivotinja and implements MozeProizvestiZvuk interface.
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include"Zivotinja.h"
#include"MozeProizvestiZvuk.h"
typedef struct PasVTableStruct{
bool (*obrisi)(void **Pas);
void (*ispisiPodatkeOZivotinji)(void *Pas);
int (*dajGodine) (void *Pas);
bool (*daLiJeVlasnikStariji) (void *Pas);
} PasVTable;
typedef struct PasStruct{
PasVTable *vTable;
int godine;
const char* vlasnik;
int godineVlasnika;
unsigned int kolikoPutaJeProizveoZvuk;
MozeProizvestiZvuk* (*getMozeProizvestiZvuk)(struct PasStruct *_this);
} Pas;
MozeProizvestiZvuk* Pas_getMozeProizvestiZvuk(Pas *_this);
void ispisiPodatkeOPsu(void *pasVoid){
Pas *pas = (Pas*)pasVoid;
printf("Pas ima %d godina, vlasnik se zove %s, vlasnik ima %d godina. \n", pas->godine, pas->vlasnik, pas->godineVlasnika);
}
int dajGodinePsa(void *pasVoid){
Pas *pas = (Pas*) pasVoid;
return pas->godine;
}
bool daLiJeVlasnikStariji(Pas *pas){
return pas->godineVlasnika >= pas->godine;
}
void Pas_obrisi(Pas **adresaPointeraPsa){
Pas *pasZaBrisanje = *adresaPointeraPsa;
free(pasZaBrisanje);
*adresaPointeraPsa = NULL;
}
struct PasVTableStruct pasVTableGlobal = {
Pas_obrisi,
ispisiPodatkeOPsu,
dajGodinePsa,
daLiJeVlasnikStariji
};
Pas* Pas_new(int godine){
Pas *z = (Pas*) malloc(sizeof(Pas));
z->godine = godine;
z->kolikoPutaJeProizveoZvuk = 0;
z->vTable = (&pasVTableGlobal);
z->getMozeProizvestiZvuk = Pas_getMozeProizvestiZvuk;
return z;
}
Pas *Pas_new_sve(int godine, int godineVlasnika, char* imeVlasnika){
Pas *pas = (Pas*) malloc(sizeof(Pas));
pas->kolikoPutaJeProizveoZvuk = 0;
pas->godine = godine;
pas->godineVlasnika = godineVlasnika;
pas->vlasnik = imeVlasnika;
pas->vTable = &pasVTableGlobal;
pas->getMozeProizvestiZvuk = Pas_getMozeProizvestiZvuk;
return pas;
}
unsigned int Pas_getBrojZvukova(Pas *_this){
return _this->kolikoPutaJeProizveoZvuk;
}
void Pas_proizvediZvuk(Pas *_this){
printf("Pas godina %d, vlasnika %s je proizveo zvuk.\n", _this->godine, _this->vlasnik);
_this->kolikoPutaJeProizveoZvuk++;
}
MozeProizvestiZvuk* Pas_getMozeProizvestiZvuk(Pas *_this){
MozeProizvestiZvuk *mozeProizvestiZvuk = (MozeProizvestiZvuk*) malloc(sizeof(MozeProizvestiZvuk));
mozeProizvestiZvuk->getKolikoPutaJeProizveoZvuk = Pas_getBrojZvukova;
mozeProizvestiZvuk->proizvediZvuk = Pas_proizvediZvuk;
mozeProizvestiZvuk->strukturaKojuMetodeInterfejsaKoriste = _this;
return mozeProizvestiZvuk;
}

Resources