Skip to content

Instantly share code, notes, and snippets.

@JonathonReinhart
Created September 2, 2015 16:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JonathonReinhart/643e463d754eb7bedb2c to your computer and use it in GitHub Desktop.
Save JonathonReinhart/643e463d754eb7bedb2c to your computer and use it in GitHub Desktop.
Object-oriented programming in C (without casts)
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
void *malloc_safe(size_t n)
{
void *p = malloc(n);
if (!p) {
fprintf(stderr, "malloc(%zd) failed\n", n);
abort();
}
return p;
}
struct type_a {
int a;
};
struct type_b {
int b;
};
enum typeid {
TYPE_A,
TYPE_B,
};
struct virt {
enum typeid typeid;
union {
char _mark[0];
struct type_a a;
struct type_b b;
};
/* Don't add anything after this union */
};
#define virt_sizeof(type) \
(offsetof(struct virt, _mark) + sizeof(type))
struct virt *new_a(int a)
{
struct virt *o = malloc_safe( virt_sizeof(struct type_a) );
o->typeid = TYPE_A;
o->a.a = a;
return o;
}
struct virt *new_b(int b)
{
struct virt *o = malloc_safe( virt_sizeof(struct type_b) );
o->typeid = TYPE_B;
o->b.b = b;
return o;
}
static void handle_a(struct type_a *o)
{
printf("%s a=%d\n", __FUNCTION__, o->a);
}
static void handle_b(struct type_b *o)
{
printf("%s b=%d\n", __FUNCTION__, o->b);
}
void handle_virt(struct virt *o)
{
switch (o->typeid) {
case TYPE_A: return handle_a(&o->a);
case TYPE_B: return handle_b(&o->b);
default:
fprintf(stderr, "Invalid type %d\n", o->typeid);
abort();
}
}
int main(void)
{
struct virt *o;
o = new_a(33);
handle_virt(o);
free(o);
o = new_b(66);
handle_virt(o);
free(o);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment