How to initialize a struct in accordance with C programming language standards

Viewed 1070953

I want to initialize a struct element, split in declaration and initialization. This is what I have:

typedef struct MY_TYPE {
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

void function(void) {
  MY_TYPE a;
  ...
  a = { true, 15, 0.123 }
}

Is this the way to declare and initialize a local variable of MY_TYPE in accordance with C programming language standards (C89, C90, C99, C11, etc.)? Or is there anything better or at least working?

Update I ended up having a static initialization element where I set every subelement according to my needs.

16 Answers

In (ANSI) C99, you can use a designated initializer to initialize a structure:

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

Other members are initialized as zero: "Omitted field members are implicitly initialized the same as objects that have static storage duration." (https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)

You can do it with a compound literal. According to that page, it works in C99 (which also counts as ANSI C).

MY_TYPE a;

a = (MY_TYPE) { .flag = true, .value = 123, .stuff = 0.456 };
...
a = (MY_TYPE) { .value = 234, .stuff = 1.234, .flag = false };

The designations in the initializers are optional; you could also write:

a = (MY_TYPE) { true,  123, 0.456 };
...
a = (MY_TYPE) { false, 234, 1.234 };

a = (MYTYPE){ true, 15, 0.123 };

would do fine in C99

Adding to All of these good answer a summary to how to initialize a structure (union and Array) in C, focused especially on the Designed Initializer.

Standard Initialization

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

p = {1.2, 1.3}; 

Designated Initializer

The Designated Initializer came up since the ISO C99 and is a different and more dynamic way to initialize in C when initializing struct, union or an array.

The biggest difference to standard initialization is that you don't have to declare the elements in a fixed order and you can also omit element.

From The GNU Guide:

Standard C90 requires the elements of an initializer to appear in a fixed order, the same as the order of the elements in the array or structure being initialized.

In ISO C99 you can give the elements in random order, specifying the array indices or structure field names they apply to, and GNU C allows this as an extension in C90 mode as well


Examples

1. Array Index

Standard Initialization

int a[6] = { 0, 0, 15, 0, 29, 0 };

Designated Initialization

int a[6] = {[4] = 29, [2] = 15 }; // or
int a[6] = {[4]29 , [2]15 }; // or
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

2. Struct or union:

Standard Initialization

struct point { int x, y; };

Designated Initialization

struct point p = { .y = 2, .x = 3 }; or
struct point p = { y: 2, x: 3 };

3. Combine naming elements with ordinary C initialization of successive elements:

Standard Initialization

int a[6] = { 0, v1, v2, 0, v4, 0 };

Designated Initialization

int a[6] = { [1] = v1, v2, [4] = v4 };

4. Others:

Labeling the elements of an array initializer

int whitespace[256] = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
                        ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };

write a series of ‘.fieldname’ and ‘[index]’ designators before an ‘=’ to specify a nested subobject to initialize

struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };

Guides

This can be done in different ways:

MY_TYPE a = { true, 1, 0.1 };

MY_TYPE a = { .stuff = 0.1, .flag = true, .value = 1 }; //designated initializer, not available in c++

MY_TYPE a;
a = (MY_TYPE) { true,  1, 0.1 };

MY_TYPE m (true, 1, 0.1); //works in C++, not available in C

Also, you can define member while declaring structure.

#include <stdio.h>

struct MY_TYPE
{
    int a;
    int b;
}m = {5,6};

int main()
{
    printf("%d  %d\n",m.a,m.b);    
    return 0;
}
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}

I have read the Microsoft Visual Studio 2015 Documentation for Initializing Aggregate Types yet, all forms of initializing with {...} are explained there, but the initializing with dot, named ''designator'' isn't mentioned there. It does not work also.

The C99 standard chapter 6.7.8 Initialization explains the possibility of designators, but in my mind it is not really clear for complex structs. The C99 standard as pdf .

In my mind, it may be better to

  1. Use the = {0};-initialization for all static data. It is less effort for the machine code.
  2. Use macros for initializing, for example

    typedef MyStruct_t{ int x, int a, int b; } MyStruct; define INIT_MyStruct(A,B) { 0, A, B}

The macro can be adapted, its argument list can be independent of changed struct content. It is proper if less elements should be initialized. It is also proper for nested struct. 3. A simple form is: Initialize in a subroutine:

void init_MyStruct(MyStruct* thiz, int a, int b) {
  thiz->a = a; thiz->b = b; }

This routine looks like ObjectOriented in C. Use thiz, not this to compile it with C++ too!

MyStruct data = {0}; //all is zero!
init_MyStruct(&data, 3, 456);

I've been looking for a nice way to initialize my struct, and I've got to using the below (C99). This lets me initialize either a single structure or an array of structures in the same way as plain types.

typedef struct {
    char *str;
    size_t len;
    jsmntok_t *tok;
    int tsz;
} jsmn_ts;

#define jsmn_ts_default (jsmn_ts){NULL, 0, NULL, 0}

This can be used in the code as:

jsmn_ts mydata = jsmn_ts_default; /* initialization of a single struct */

jsmn_ts myarray[10] = {jsmn_ts_default, jsmn_ts_default}; /* initialization of
                                                    first 2 structs in the array */
Related