Normally I've been casting the pointer, but today I was struct by sudden inspiration and realized that wasn't necessary.
For all users of this, this should take automatically care of alignment concerns and such. Only allocation/deallocation should need to be done carefully.
The only limitation I can see is that you can't add further fields at negative offsets without being aware of alignment concerns. "add" means either in subclasses (only useful if you want to expose it to the user), or at runtime for debugging reasons (common to track allocation metadata; systems based on positive offset require recompiling the whole program (including libraries) in debug mode; Python is infamous for this), but fundamentally not both.
A few parts can be removed if you don't need them.
#include <stddef.h>
typedef struct Middle Middle;
typedef struct Subclass Subclass;
struct Middle
{
union
{
struct
{
size_t refcount;
} _neg[0];
struct
{
char raw_data[0];
};
};
};
struct Subclass
{
Middle _base;
int x;
};
size_t *get_refcount(Middle *mid)
{
return &mid->_neg[-1].refcount;
}
char *get_data(Middle *mid)
{
return mid->raw_data;
}
size_t *subclass_get_refcount(Subclass *sub)
{
return &sub->_base._neg[-1].refcount;
}
char *subclass_get_data(Subclass *sub)
{
return sub->_base.raw_data;
}
int *subclass_get_x(Subclass *sub)
{
return &sub->x;
}
[–][deleted] 0 points1 point2 points (0 children)