GitHub - small-c/obj.h: 🚀 OOP in pure C with a single-header (original) (raw)

obj.h

A single-header supports OOP in pure C.
Using power of preprocessor and hacking on assembly to unlock the limits.

Foo f = new(Foo)(10); // create Foo instance assert(f->get() == 10); // get value f->base.release(); // release

Features

Usage

C++ comparison:

// C++ native OOP // C with obj.h class Foo { | class(Foo, public( public: | int (*get)(); Foo(int bar); | ), private( int get(); | int bar; private: | )); int bar; | }; | ctor(Foo)(int bar) { | obj_setup(Foo); Foo::Foo(int bar) { | obj_bind(Foo, get); this->bar = bar; | self->bar = bar; } | obj_done(Foo); | } int Foo::get() { | return this->bar; | method(Foo, int, get)() { } | obj_prepare(Foo); | return self->bar; | } | Foo *f = new Foo(15); | Foo f = new(Foo)(15); f->get(); | f->get(); delete f; | f->base.release();

Platform support:

GCC 4+ MSVC 14+ Clang 5+ TCC 0.9
Windows (x86 / x64) ✅ ✅ ✅ ✅
Linux (i386 / x86_x64) ✅ _ ✅ ✅
Mac OSX (i386 / x86_64) ✅ _ ✅ _

How it works?

We can't explain in detail, but something like binding this to a function in JavaScript.

Simulate a simple class with struct:

struct A { void (* todo)(); // method };

And we have a static function:

Next, bind A instance (aka this) to fn_todo 🙄

binded_todo = bind(fn_todo, myA);

Finally 😎

myA->todo = binded_todo; myA->todo(); // call it like a method

Closure function?

Function template:

static void fn_todo() { volatile size_t self = ...; ...

Disassemble:

; prolog mov rax, ... mov QWORD PTR [rbp-8], rax ...

Generated function:

[copied prolog]

x86 | mov eax, [data] | jmp [addr] x86_64 | mov rax, [data] | push rax | mov rax, [addr] | jmp rax

Refs:

How we provide classes, public/private?

See obj.h for more.

ko-fi