Plan9 compiler extensions in gcc 4.6
gcc.gnu.org
gcc.gnu.org
Right now, say a library I'm using exposes this:
struct lib_struct {
int foo;
char* bar;
};
typedef void (*lib_callback)(struct lib_struct*);
extern void lib_fn(struct lib_struct* obj, lib_callback cb);
If I want to use that in one of my own data structures: struct my_struct {
struct lib_struct lib_st;
int my_own_data;
};
static void my_callback(struct lib_struct* lib_st)
{
// plan9 extension does not appear to help here...
struct my_struct* me = container_of(lib_st, struct my_struct, lib_st);
printf("%i\n", me->my_own_data);
}
/* elsewhere... */
struct my_struct* m = /* ... */;
// ... though it would here:
lib_fn(&m->lib_st, my_callback);
It'd be handy to be able to condense the container_of line somewhat, while maintaining (some) type safety.[1] http://www.kroah.com/log/linux/container_of.html - I use a similar macro that preserves NULL pointers.
[1] http://super.para.media.kyoto-u.ac.jp/~tasuku/sc/index-e.htm...
So ideas from Plan 9 will always have an audience. As for top of the front page, it's just how things bubble up and down, no cause for alarm.
enum MyStructType { MyInt, MyFloat };
struct my_struct
{
enum MyStructType type;
union
{
struct {
int my_int;
} as_int;
struct {
float my_float;
} as_float;
} d;
};
To get to the actual data, in standard C89/99 you need to do this: struct my_struct* s = /* ... */;
if (s->type == MyInt)
printf("%i\n", s->d.as_int.my_int); /* <- !!!!!! */
else
printf("%f\n", s->d.as_float.my_float); /* <- !!!!!! */
With the extension, the inner union and struct members are added to the outer struct/union's namespace: enum MyStructType { MyInt, MyFloat };
struct my_struct
{
enum MyStructType type;
union
{
struct {
int my_int;
};
struct {
float my_float;
};
}; /* note: no name */
};
Now the access code is much nicer: struct my_struct* s = /* ... */;
if (s->type == MyInt)
printf("%i\n", s->my_int); /* <- !!!!!! */
else
printf("%f\n", s->my_float); /* <- !!!!!! */
The second part extends this to typedefs, while the third part, the Plan9 addition (which is presumably the reason for the HN submission) gives you an implicit struct pointer conversion for structs composed of other structs, a bit like C++'s implicit pointer conversion for inheritance. The page has an example of this already: struct s1 { int a; };
struct s2 { struct s1; };
extern void f1 (struct s1 *);
void f2 (struct s2 *p) { f1 (p); }
This is how you'd normally have to do it: struct s1 { int a; };
struct s2 { struct s1 my_s1; }; // <- note non-anonymous struct field
extern void f1 (struct s1 *);
void f2 (struct s2 *p) { f1 (&p->my_s1); } // <- my code is always littered with this idiom
All of this might not seem like much, but complicated data structures really aren't a forte of the C syntax. A bit of sugar alleviates at least some of the endless repetition.Similarly, one can pass pointers to objects that contain a type as if it was the type itself, which is the same thing that inheritance allows. Of course, here there is no difference between containment and inheritance, you can use it as you desire.