Reputation: 15
Is there a way to initialize the whole array of structures (maybe using compound literals) after it is being declared?
typedef struct
{
int a;
int b;
} tStruct;
/* Array of structures in declared in global scope, but not initialized */
tStruct myStruct[3];
void init()
{
/* We want to initizlize the array with specific values*/
/* using compound literals to initialize the whole array doesn't work */
myStruct = (tStruct[])
{
{1, 2},
{3, 4},
{5, 6}
};
}
Upvotes: 1
Views: 1173
Reputation: 60163
Arrays aren't R values, so you can't copy them via assignemnt. But you can use memcpy
#include <string.h>
void init(void)
{
memcpy(&myStruct,(tStruct[]) { {1, 2}, {3, 4}, {5, 6} }, sizeof(myStruct));
}
The code generated by an optimizing compiler shouldn't be much worse than what you'd get with
void init2(void)
{
myStruct[0] = (tStruct){1,2};
myStruct[1] = (tStruct){3,4};
myStruct[2] = (tStruct){5,6};
}
or
void init3(void)
{
myStruct[0].a = 1, myStruct[0].b = 2;
myStruct[1].a = 3, myStruct[1].b = 4;
myStruct[2].a = 5, myStruct[1].b = 6;
}
Gcc and clang are well capable of eliding an unnecessary compound variable like that in favor of assigning individual components directly.
https://gcc.godbolt.org/z/j9f37j
The biggest downside of the memcpy
approach is that it's a bit brittle and type-unsafe (and can result in out-of-bounds reads/writes if the unenforced type compatibility is violated).
If your C dialect has __typeof, then with some macro trickery you should be able to almost get around this C language limitation:
#include <string.h>
#define assignAnything(DestPtr,SrcPtr) ((void)((__typeof(SrcPtr)){0} = (__typeof(DestPtr)){0}) /*typecheck*/, memcpy(DestPtr, SrcPtr, sizeof(*(DestPtr))))
/* A Ptr-less version:
#define assignAnything2(Dest,Src) ((void)((__typeof(&(Src))){0} = (__typeof(&(Dest))){0}), memcpy(&(Dest), &(__typeof(Src)){Src}, sizeof(Dest)))
doesn't always work, unfortunately */
int main()
{
int d[3][2][1]={0};
int const s[3][2][1] = {0};
assignAnything(&d,&s); //works
#if NOPE
assignAnything(&s,&d); //will (correctly) compile-time fail because s has more qualifs (const) than d
#endif
}
Upvotes: 2
Reputation: 6487
For arrays, compound literals only work on the statement declaration. You have to use individual assignments, loops, memcpy() or memset() to initialize arrrays and structs after that.
Example, to obtain same result:
typedef struct
{
int a;
int b;
} tStruct;
/* Array of structures in declared in global scope, but not initialized */
tStruct myStruct[3];
void init()
{
/* Initizlize the array with specific values*/
int i;
const tStruct second_element = { 3, 4 };
// member by member...
myStruct[0].a = 1;
myStruct[0].b = 2;
// using struct copy.
myStruct[1] = second_element;
// or a loop...
for (i = 2; i < 3; ++i) // I know, there are only 3 elmments, but you get
// the idea..
{
myStruct[i].a = (2 * i) + 1;
myStruct[i].b = myStruct[i].a + 1;
}
}
Upvotes: 0
Reputation: 2103
No, that does not work as you cannot assign one array to another.
But you can use memcpy
to get around it
void init()
{
tStruct data[3] = {
{1, 2},
{3, 4},
{5, 6}
};
memcpy(mystruct, data, sizeof(mystruct));
}
But, be careful as the size of the data must match exactly.
Upvotes: 1