Let's say a have
struct table { int foo, bar, baz; };
static struct table const A = { .foo = 1, .bar = 2, .baz = 3 };
how could I declare B to be the exact same definition of A but with one change?
For instance what I would like to write is something like
static struct table const B = A, { .bar = 42 };
I am looking for a solution, if any, simpler than the following workaround:
#define A_DEFS .foo = 1, .bar = 2, .baz = 3
static struct table const A = { A_DEFS };
#define B_DEFS A_DEFS, .bar = 42
static struct table const B = { B_DEFS };
Try :
static struct table const B = { A.foo, .bar = 42, A.baz };
SparKot's answer let me come to this slightly more convenient solution:
struct table { int foo, bar, baz; };
#define BASE(X) X.foo, X.bar, X.baz
static struct table const A = { .foo = 1, .bar = 2, .baz = 3 };
static struct table const B = { BASE(A), .bar = 42 };
static struct table const C = { BASE(B), .baz = 24 };
Related
I found a GNU C documentation on flexible arrays, and they say that you can initialize them like that:
struct foo { int x; int y[]; };
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; // Valid.
struct bar b = { { 1, { 2, 3, 4 } } }; // Invalid.
struct bar c = { { 1, { } } }; // Valid.
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // Invalid
But when I try to do the first valid case (with struct a), gcc throws error: Initialization of flexible array member is not allowed. So is this deprecated or is there another way to do it without malloc?
typedef enum
{
ONE = 1,
TWO = 2,
THREE = 3
}Count_t;
typedef enum
{
RED = 0,
BLUE = 1,
GREEN = 2
}Color_t;
typedef struct
{
Count_t Count_en;
Color_t Color_en;
}Grp_t;
Grp_t const Grp_ena[]=
{
{ ONE, RED },
{ TWO, BLUE },
{ THREE, GREEN}
};
typedef struct
{
unsigned int num;
Grp_t * Grp_stp;
}Try_t;
Try_t const Try_sta[] =
{
{ 7, &Grp_ena[0] },
{ 8, &Grp_ena[1] },
{ 9, &Grp_ena[2] },
};
int main()
{
Try_t **p = Try_sta;
}
Using double pointer **p , I want to access the elements of LUT Try_sta. With single dimensional pointer I am able to access the struct array elements. But with 2d pointer I failed to access. Is there any proper way to do it?
Suppose I have something like:
typedef struct
{
int parameter1;
int parameter2;
void (fp*)(void);
} STATE_T;
and I have various sets of default parameters to start the program(or this segment of the program) in different states.
STATE_T State;
void InitState1()
{
State.parameter1 = 123;
State.parameter2 = 321;
State.fp = Function1;
}
void InitState2()
{
State.parameter1 = 0;
State.parameter2 = 1;
State.fp = Function2;
}
or would it better to use const structs
const STATE_T STATE1 =
{
123,
321,
Function1
}
const STATE_T STATE2 =
{
0,
1,
Function2
}
I suppose in the 2nd case either a pointer can be used or a function to copy a selection of settings:
STATE_T * StatePtr;
StatePtr = &STATE1;
or
void InitState(STATE_T s)
{
State.parameter1 = s.parameter1;
State.parameter2 = s.parameter2;
State.fp = s.fp;
}
After typing out all the examples, it seems like, in the case I want to change all parameters at the same time, using a pointer to const structs would be more efficient, while an init functions would be better for only updating selected parameters that would be relevant. Are there any other advantages or differences to be aware of?
I typically declares some static versions statically ie
static State State1 = {
.paramater1 = 123,
.parameter2 = 321,
.fp = NULL,
};
static State State2 = {
.paramater1 = 999,
.parameter2 = 111,
.fp = NULL,
};
Then in an init function assign the statics to get the defaults...
static State * newState(int state) {
State *foo = calloc(1, sizeof(State));
assert(foo != NULL);
if(state == 1) {
*foo = State1;
foo->fp = function_fp1;
}
else {
*foo = State2;
foo->fp = function_fp2;
}
return foo;
}
I have these 2 structs:
struct Params {
int a;
int b;
};
struct Foo {
const struct Params settings;
int state;
};
The settings member is const as a hint that it should not be changed once a struct Foo has been created and initialized.
And I want to dynamically allocate this struct, e.g.
struct Foo * new_foo(void)
{
struct Foo *n = malloc(sizeof *n);
if (n) {
n->settings.a = SETTING_A;
n->settings.b = SETTING_B;
...
}
return n;
}
Now, this will not compile due to settings being const. What is a proper way to
initialize such a struct in this manner? Or is it better to not declare the settings member as const?
The memory is allocated (and thus, not constant), so it is legal to cast const away:
struct Foo * new_foo(void)
{
struct Foo *n = malloc(sizeof *n);
if (n) {
struct Params *s = (void *)&n->settings;
s->a = SETTING_A;
s->b = SETTING_B;
}
return n;
}
Here is one way to do it:
struct Foo *new_foo(void)
{
static struct Foo foo =
{
.settings =
{
.a = SETTING_A,
.b = SETTING_B
},
.state = ...
};
struct Foo *n = malloc(sizeof *n);
memcpy(n, &foo, sizeof *n);
return n;
}
Here is another way to do it:
struct Foo *new_foo(void)
{
static struct Params settings =
{
.a = SETTING_A,
.b = SETTING_B
};
struct Foo *n = malloc(sizeof *n);
memcpy((struct Params*)&n->settings, &settings, sizeof settings);
n->state = ...;
return n;
}
struct A{
int a; int b;
};
static const struct A a = {.a1 = 1, .a2 = 42};
struct B{
struct A[666][510]
};
static const struct B b;
I would like to initialize b with copies of a. However, I cannot touch static const things with memcpy(). And I need b to be static const, because that way it gets put into flash and not ram memory.
How do I make this work. The compiler is arm-none-eabi-gcc with -std=c89, I think.
You can try this, though it works specifically for the dimensions that you specify (666 x 510):
#define X001 {1,42}
#define X002 X001,X001
#define X004 X002,X002
#define X008 X004,X004
#define X016 X008,X008
#define X032 X016,X016
#define X064 X032,X032
#define X128 X064,X064
#define X256 X128,X128
#define Y001 {X256,X128,X064,X032,X016,X008,X004,X002}
#define Y002 Y001,Y001
#define Y004 Y002,Y002
#define Y008 Y004,Y004
#define Y016 Y008,Y008
#define Y032 Y016,Y016
#define Y064 Y032,Y032
#define Y128 Y064,Y064
#define Y256 Y128,Y128
#define Y512 Y256,Y256
static const struct A a = X001;
static const struct B b = {{Y512,Y128,Y016,Y008,Y002}};
I recommend that you put these arrays in a separate module in order to achieve encapsulation. Then inside that module you do not need to make B a const but make it static instead.
Any access to this data must be done via getters and setters like this:
mydata.h
#define BA_SIZE 666
struct A{
int a; int b;
};
struct B{
struct A stuff[BA_SIZE];
};
void init(void);
struct A * getB(unsigned int i);
void setB(unsigned int i, struct A element);
mydata.c:
#include "mydata.h"
static const struct A a = {.a = 1, .b = 42};
static struct B b;
void init(void)
{
int i;
for(i=0; i<BA_SIZE; i++) {
b.stuff[i] = a;
}
}
struct A * getB(unsigned int i)
{
return(&b.stuff[i]);
}
void setB(unsigned int i, struct A element)
{
if (i > BA_SIZE) { return; }
b.stuff[i].a = element.a;
b.stuff[i].b = element.b;
}
main.c:
#include <stdio.h>
#include "mydata.h"
int main(void)
{
init();
unsigned int num=1;
struct A * something = getB(num);
printf("element [%u] a=%i b=%i \n", num, something->a, something->b);
return(0);
}
On linux this complies with gcc -std=c89 (don't know about arm cross compiler)
typedef struct A{
int a; int b;
} TA;
typedef struct ARR3 {
TA a[3];
} TARR3;
typedef struct ARR33 {
TARR3 b[3];
} TARR33;
static const TA a = {.a = 1, .b = 42};
TARR33 aa = {
.b[0] = { .a[0] = {.a = 1, .b = 1}, .a[1] = {.a = 2, .b = 2}, .a[2] = {.a = 3, .b = 3} },
.b[1] = { .a[0] = {.a = 4, .b = 4}, .a[1] = {.a = 5, .b = 5}, .a[2] = {.a = 1, .b = 2} },
.b[2] = { .a[0] = {.a = 1, .b = 1}, .a[1] = {.a = 1, .b = 2}, .a[2] = {.a = 1, .b = 2} }
};
main()
{
return 0;
}