kung-foo
Kung - F00
Kickass programming techniques
kung-foo


Anonymous Arrays in C

This is some technique i discovered around march '04 while looking for a smart way to encode VTBL for memory classes in Clicker32 microkernel. Due to the large amount of new KickassProgrammingTechniques it allows with a regular ANSI C compiler (gcc, for instance) i decided to create this page ...

So you all know that an array in C is roughly the same thing as a pointer to its base member, except at initialization. You can easily create a char array[ ]="this is a string" and then have char* str = array without any additionnal code. You also know it is possible to initialize such array even when it is static with char array[]={1,2,3,4}.

So what's new ? C also allows you to insert the reference of an array into a (static or not) pointer without requiring that the array has a name... In other words, what was written yesterday as
int iarray[]={1,2,3,4};
int* iaptr=iarray;

can also be written
int* iaptr=(int[]){1,2,3,4};
With existing variables, you can extract the address with &variable, but how could you do so for an integer, for instance ? there are several functions (for instance setsockopt) that expect a pointer to an int rather than an int ... you cannot write &1 ... but you can write (int[]){1}...

so the boring ...
{
    int yes=1;
    setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}
becomes
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));

Passing a Variable Amount of Arguments

Let's say you have a function that should work on N argument, where N may vary and is usually unpredictable when you're writing the function ... You can of course use <stdarg.h> to solve this issue and use the va_start, va_end and va_arg do their job. However, these macros are not really straightforward to use and you cannot restrict the type of the arguments.

void yourFunction(int nb, ...) {
    va_list vl=va_start(nb);
    while (nb) x=va_arg(vl,type);
}
yourFunction(4,val1,val2,val3,val4);
is just nice while
void myFunction(type* values) {
    while(*values) x=*values++;
}
myFunction((type[]){val1,val2,val3,val4,0});
can also check all the values are of the requested type :-p Moreover, this scheme is not limited to arrays. If you're required to pass a structure of parameters (which is commonly used together with a 'present fields' flags in MS libraries), you can now create the structure right while you're calling the function rather than requiring a local variable ...
void myFunction(int present, struct params* p) {
   if (!(present&SOME_FIELD)) p->field=DEFAULT_VALUE;
   ...
}

myFunction(SOME_FIELD|OTHER_FIELD,
           (struct params[]){{field:value, otherfield:v2}});
note the double round braces as initializing an array require that items are between round braces and initializing a structure also requires roundbraces around the <field>:<value> list ...


Creating Static Linked-Lists

If you have worked a bit with linked list you certainly observe how painful it is to create an initial list that will work with the 'other' lists. The traditionnal programmer will create an array of items and use a runtime loop to build the list from the array ...
struct llist { atom a; struct llist* next;};
atom x[]={a1,a2,...,aN,nil};

struct llist *lst=NULL;

don_t_forget_to_call_this()
{
   atom *p;
   struct llist *l;
   for (p=x;*p!=nil;p++) {
      l=malloc(sizeof(struct llist));
      l->a=*p; l->next=lst; lst=l;
   }
}

In addition from requiring an extra array, you need to write the extra function which will perform plenty of malloc at run-time. If one *really* want to write the linked list in the data segment, (s)he will have to write something like
struct llist iN={aN,NULL},
   ...,
   i2={a2,&i3},
   i1={a1,&i2},
   *lst=&i1;

which introduce maaany useless symbols. Once again, anonymous arrays (of one element) can save us with
#define cons(x,y) (struct llist[]){{x,y}}
struct llist *lst=cons(a1, cons(a2, co...ns(aN,NULL) ... ));
which will resolve in a nice linked list. (i took 'cons' in honour of the Scheme keyword for creating a pair). The macro is more than suggested here if you want something useful. If you have a lot


Creating complex structures using anonymous arrays

The initial use i made of anonymous arrays is to allow the creation of complex data structures without having to give all their components a dedicated name. Let's say you have a group structure that is made of a name and a collection of items, you could use extensible arrays (but they're GCC-specific iirc) and write

struct group {
   char *name;
   struct item items[0];
};

struct group grp={
    "groupname",{
        {<item1>},{<item2>},
        ... , {<itemN>},{<void_item>}
    }
};


which works quite fine. However, you'll find yourself in big troubles if you ever try to have items themselves being union item { struct atom a; struct group g}. With some versions of gcc (2.95.3), you'll be able to build such groups, while on other (3.x) you won't. Moreover, such groups will be quite hard to follow as items may have variable size. An alternative would be to declare the group as made of a name and an array of pointers towards items (rather than items themselves) so that all entries in the group's list are equivalently-sized.

In 'traditionnal' C programming, this requires you to name all your items and have something like
struct group {
   char *name;
   struct item* items[0];
};

struct item i1={<item1>}, i2={<item2>},
        ... ,iN={<itemN>};

struct group = {
    "groupname", { &i1, &i2, &i3, ... , &iN }
};

While the kung-f00 master knows about anonymous arrays and do
#define _(x) (struct item[]){{x}}
struct group = {"groupname", {_(<item1>),_(<item2>),
        ...,_(<itemN>),NULL}};




So that's all i can find for now ... Hope you liked those "new" programming techniques.
more to come soon
kungf00m4st3r