Last year, I discovered, thanks to the book “C, A Reference Manual“, a great C99 feature: designated initializers. Designated initializers allow you to initialize components of an aggregate (structure, union or array) by specifying their names within an initializer list.

Arrays initialization

What most people normally use to initialize an array is the following idiom:

int v[4] = { 4, 2, 1, -5 };

in which you need to initialize each component of the array sequentially. Designated initializers allow you to specify which component of the array you want to initialize. Thus, we could write the line above as:

int v[4] = { [1] = 2, [2] = 1, [0] = 4, [3] = -5 };

Note that we have specified the component indexes which has allowed us to initialize the array with our desired order. If we do not initialize all the components, those not initialized will get 0 values. We can also mix both methods, so the line below would be also correct:

int v[4] = { [1] = 2, 1, [3] = -5 };

in which the component not referenced goes right after the named one.

A possible use of this kind of initializations would be a mapping between a list of identifiers and a list of strings.

// The public interface typedef enum { id_one, id_two, id_three } id_t; extern char const* string_by_id (id_t id); // The private implementation static char const* strings[] = { [id_one] = "identifier one", [id_two] = "identifier two", [id_three] = "identifier three" }; char const* string_by_id (id_t id) { return strings[id]; }

Structures and unions initialization

Designated initializers are also useful to initialize components of structures and unions by their name. In this case, the component to be initialized takes the form .c, where c is the name of the component. So, suppose we have the following structure:

struct point { float x; float y; float z; };

we could initialize each component of a struct point variable like this:

struct point my_point = { .x = 0.34, .y = 0.98, .z = 1.56 };

With unions, we will use the same method, so having the following union:

union integer { unsigned char int_8; unsigned short int int_16; unsigned long int_32; };

we can initialize it by any of its components:

union integer value = { .int_16 = 24000 };

Finally, we can merge both cases, so we can have arrays of structures or unions that can be initialized using designated initializers:

struct point pointvector[3] = { [0].x = 0.34, [0].y = 1.78, [0].z = 3.18, [1] = { .x = 3.5, .y = 6.89 }, [2] = { .y = 2.8, 1.23 } };

Share this: Twitter

Facebook

Like this: Like Loading... Related