Reputation: 13
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
Reputation: 754090
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.
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