>>109216127
The linux kernel (and other projects inspired by it) use something called container_of for a much more elegant version of that.
#include <stddef.h> // offsetof
#include <stdio.h>
#include <stdlib.h>
/* This is written using a GNU extension ({ }) and just copied
* from the examples you get on google,
* but you can write a more standards-conforming version.
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct sub_type {
int foo;
};
struct parent_type {
struct sub_type sub;
int bar;
};
struct sub_type *new()
{
struct parent_type *p = malloc(sizeof *p);
p->sub.foo = 1;
p->bar = 2;
return &p->sub;
}
void print(struct sub_type *s)
{
struct parent_type *p = container_of(s, struct parent_type, sub);
printf("%s: %d\n", __func__, p->bar);
}
void add(struct sub_type *s)
{
struct parent_type *p = container_of(s, struct parent_type, sub);
++p->bar;
}
int main()
{
struct sub_type *s = new();
printf("%s: %d\n", __func__, s->foo);
print(s);
add(s);
print(s);
}
I personally wouldn't use this for some kind of partial data hiding. If that's what you really need, I think
struct my_opaque_type;
struct the_public_bit {
...
};
struct my_opaque_type *new();
struct the_public_bit *get_public(struct my_opaque_type *);
Would be less hassle.
container_of is more suited to allowing for composability. It kind of changes your entire perceptive on how you can write C.