Skip to content

Instantly share code, notes, and snippets.

@dhilst
Created February 22, 2020 05:53
Show Gist options
  • Save dhilst/d5f3ca90a12840b4f17981f4e15674bd to your computer and use it in GitHub Desktop.
Save dhilst/d5f3ca90a12840b4f17981f4e15674bd to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
/*
* You can get the offset of a member on a struct by dereferencing that member on
* address 0 of such structure.
*/
#define offset_of(type, member) ((unsigned long) &((type *)0)->member)
#define selfref(type, r, member) \
((type *) r + (r->member))
typedef struct {
int i;
unsigned long i_ptr;
} T;
typedef struct {
int i;
int* i_ptr;
} T2;
T *new_T(void)
{
T *n = malloc(sizeof(T));
assert(n);
n->i = 0;
n->i_ptr = offset_of(T, i);
*selfref(int, n, i_ptr) = (int) n->i;
return n;
}
int main(int argc, char **argv)
{
// allocate or structs
T *a = new_T(), *b = new_T();
// do stuff on on a
a->i = 42;
// move a -> b
memcpy(b, a, sizeof(*b));
free(a);
// b is safe, as on as we know how to dereference it
assert(b->i == 42);
assert(*selfref(int, b, i_ptr) == 42); // we need some sort of magic
// to dereference it, but is
// possible at compile time!
// The traditional way
T2 *c = malloc(sizeof(T2)), *d = malloc(sizeof(T2));
assert(c);
assert(d);
// init it by hand
c->i = 0;
c->i_ptr = &c->i;
// do stuff on c
c->i = 42;
// move c -> d, c is freed
memcpy(d, c, sizeof(*d));
free(c);
// This is okay since int is move safe, we just copy it
assert(d->i == 42);
assert(*(d->i_ptr) == 42); // this will fail becase i_ptr points
// to invalid memory
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment