3

I have the following nested struct definition in my .h file:

struct PARAM
{
    uint8_t data1;
    uint8_t data2[2];
    uint8_t data3[2];
};

struct CONFIG
{
    uint8_t data4;
    struct PARAM par1;
    struct PARAM par2;
};

In my main.c file I declare the following array:

struct CONFIG settings[100];

and I try to initialize the first element as follows:

settings[0].data4 = 0x01;
settings[0].par1 = {0x01,{0x01,0x01},{0x05,0x06}};
settings[0].par2 = {0x01,{0x01,0x01},{0x05,0x06}};

But I get the following error for the setting[0].par1 line:

Expected expression.

Does anyone know what I am doing wrong?

Peter Duniho
  • 111
  • 5
syn_dm
  • 59
  • 1
  • 5
  • 3
    shouldn't it be settings[0] instead of setting? – Michel Keijzers Mar 16 '20 at 11:21
  • Your declaration for the CONFIG structure has two "par1" internal declarations. – Michael Karas Mar 16 '20 at 11:24
  • 9
    You need to study the difference between initialization and assignment. The code you have posted is assignment, yet you use initializer lists. – Lundin Mar 16 '20 at 11:29
  • sorry guys, you are right I was probably not clear enough. What I am looking for is a way to initialize a struct with many fields in the most compact possible way without accessing every single content. – syn_dm Mar 16 '20 at 11:39
  • 1
    Are all the settings different, or are most of them some default value, and if so, which? Also, which C compiler? –  Mar 16 '20 at 14:30

2 Answers2

13

From C99 onwards, C has support for what the standard calls 'compound literals'.
You use them like this:

settings[0].par1 = (struct PARAM) {0x01,{0x01,0x01},{0x05,0x06}};

You can in fact fill the entire settings[0] structure at once:

settings[0] = (struct CONFIG) {
    0x01,
    {0x01, {0x01, 0x01}, {0x05, 0x06}},
    {0x01, {0x01, 0x01}, {0x05, 0x06}}
};

You can also specify the fields by name, for increased readability:

settings[0] = (struct CONFIG) {
    .data4 = 0x01,
    .par1 = {
        .data1 = 0x01,
        .data2 = { 0x01, 0x01 },
        .data3 = { 0x05, 0x06 }
    },
    .par2 = {
        .data1 = 0x01,
        .data2 = { 0x01, 0x01 },
        .data3 = { 0x05, 0x06 }
    }
};

Compound literals can be used in other places too, such as in function calls.

fun((struct PARAM) {0x01,{0x01,0x01},{0x05,0x06}});

In an initialization, you can also initialize the entire settings array at once:

struct CONFIG settings[] = {
    {
        .data4 = 0x01,
        .par1 = {
            .data1 = 0x01,
            .data2 = { 0x01, 0x01 },
            .data3 = { 0x05, 0x06 }
        },
        .par2 = {
            .data1 = 0x01,
            .data2 = { 0x01, 0x01 },
            .data3 = { 0x05, 0x06 }
        }
    },
    /* The rest of the elements go here. */
};
SvdB
  • 246
  • 1
  • 4
5

In the C language this type of text:

{0x01,{0x01,0x01},{0x05,0x06}};

Is only used when initializing the structure contents as an initializer on the declaration of the variable. It would not be used in an assignment statement.

You would have to type out the fully qualified name for each element of the structures if you want to do assignments. You could do assignments to one of the PARAM type structure variables and then assign that like:

settings[0].par1 = inited_param;

ReGuess
  • 3
  • 2
Michael Karas
  • 57,328
  • 3
  • 71
  • 138
  • thank you @michael, thank you for your answer, the real struct I am working on has many fields therefore I would like to initialize in the most compact way. If I define a single struct element such as struct CONFIG settings = {0x01,{0x01,0x01},{0x05,0x06}}; it works. So this means that if I want to do the same of N array I have to do something like struct CONFIG settings[2] = { {0x01,{0x01,0x01},{0x05,0x06}}, {0x01,{0x01,0x01},{0x05,0x06}}}; ? – syn_dm Mar 16 '20 at 11:34
  • No. You can fully initialize the whole "struct CONFIG settings =" with one initializer as long as you properly place all your { } and commas correctly. – Michael Karas Mar 16 '20 at 11:37
  • 1
    @syn_dm If you're wanting to initialize all the elements of the array to the same set if values then you could use a macro like #define INIT {0x01,{0x01,0x01},{0x05,0x06}} then struct CONFIG settings[2] = {INIT, INIT}; for a little less typing. – brhans Mar 16 '20 at 15:33
  • Sometimes when initializing large arrays of structures, especially when there is an identifiable pattern, it can be efficient to use program code with loops to set things up. – Michael Karas Mar 16 '20 at 16:42
  • You can also use function-like macros if you want to hide some of the complexity and make things more configurable. – Artelius Mar 17 '20 at 05:20