user2991509
user2991509

Reputation: 13

Initializing and using struct members inside another struct

I need to use a struct (struct1), that was previously declared, inside a new struct (struct2). Also I want to initialize it, and use some of the members of struct1 to initialize other members of struct2.

Specifically, I want to set values for struct1 and use some of those values to define the sizes of other members of struct2

I tried what is shown in the code, but I don't get why it isn't working.

typedef struct ytxModule{
    uint8_t nEncoders;
    uint8_t nDigital;
    uint8_t nAnalog;
    uint8_t nLedsPerControl;
};

typedef struct{
    ytxModule components = {4, 0, 0, 16};

    // encoder pin connections to MCP23S17
    uint8_t encPins[components.nEncoders][2] = {
      {1, 0},  
      {4, 3},   
      {14, 15},  
      {11, 12}   
    };
    // buttons on each encoder
    uint8_t encSwitchPins[components.nEncoders] = { 2, 5, 13, 10 }; 

}ytxE41Module;

The error message I get is:

sketch\headers/modules.h:52:37: error: invalid use of non-static data member '<anonymous struct>::components'

  ytxModule components = {4, 0, 0, 16};

                                     ^

sketch\headers/modules.h:55:18: error: from this location

  uint8_t encPins[components.nEncoders][2] = {

Any help will be appreciated :)

Upvotes: 0

Views: 261

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754090

Minimum necessary changes

You can't mix a typedef with initializers — at least, not in C. You also can't have structure types where the size varies depending on the data in the structure — at least, not without using one (and only one) flexible array member (FAM), but your code attempts to use two variable arrays (so they can't be FAMs).

You need something more like:

typedef struct ytxModule{
    uint8_t nEncoders;
    uint8_t nDigital;
    uint8_t nAnalog;
    uint8_t nLedsPerControl;
} ytxModule;  // Add name for typedef

typedef struct{
    ytxModule components;
    uint8_t encPins[4][2];
    uint8_t encSwitchPins[4]; 
} ytxE41Module;

ytxE41Module module = {
    .components = {4, 0, 0, 16},
    .encPins = {
      {1, 0},  
      {4, 3},   
      {14, 15},  
      {11, 12}   
    },
    .encSwitchPins = { 2, 5, 13, 10 },
}; 

This won't change shape if you initialize .components.nEncoders to a value other than 4. Depending on your needs, you could consider replacing the hard-coded 4 with a compile-time changeable value, but you'd also need a way to resize the initializer arrays to match, which is likely to be fiddly at best, inscrutable at worst. It isn't clear how the initializer values are established.

Using a flexible array member

If you want to use a flexible array member, you'll have to organize a type to hold an array for the encSwitchPins and encPins data, and use different notation to access the elements of the FAM.

typedef struct ytxModule{
    uint8_t nEncoders;
    uint8_t nDigital;
    uint8_t nAnalog;
    uint8_t nLedsPerControl;
} ytxModule;

typedef struct
{
    ytxModule components;
    struct
    {
        uint8_t encPins[2];
        uint8_t encSwitchPins;
    } pins[]; 
} ytxE41Module;

You can no longer use an initializer for this data type; you will dynamically allocate the memory and then assign values to the allocated data:

// Data used for initializing structure
int n_pins = 4;
uint8_t encPins[][2] = {
    {  1,  0 },  
    {  4,  3 },   
    { 14, 15 },  
    { 11, 12 },   
};
uint8_t switchPins[] = { 2, 5, 13, 10 };

// Allocate and check allocation
ytxE41Module *mp = malloc(sizeof(*mp) + n_pins * sizeof(mp->pins[0]));
if (mp == NULL)
    return NULL;

// Assign values to allocated structure
mp->components = (ytxModule){ n_pins, 0, 0, 16};
for (int i = 0; i < n_pins; i++)
{
    for (int j = 0; j < 2; j++)
        mp->pins[i].encPins[j] = encPins[i][j];
    mp->pins[i].encSwitchPins = switchPins[i];
}

If you tag the embedded structure type, you could initialize an array of that type and use memmove() (or memcpy()) to move copy a separate array into your FAM structure. Etc. It is much simpler if the amount of data in the structure is fixed (e.g. at 4 elements in the array), as shown in the first part of the answer.

Upvotes: 2

Related Questions