C struct compound initialization without setting everything to zero - c

Is there any syntax similar to doing something like this
typedef struct foo
{
int X;
int Y;
int Z;
} foo;
int main()
{
// Initialize everything
foo Variable = (foo){
.X = 10;
.Y = 15;
.Z = 20;
};
// Assign the X and Y variables, but keep Z the same
Variable = (foo){
.X = 15;
.Y = 20;
// .Z stays the same
};
}
Would be nice to have this type of QOL syntax instead of having to type
int main()
{
foo Variable = {bla bla};
// Keep having to type Variable. to access struct members
Variable.X = 10;
Variable.Y = 15;
}
This gets really annoying with structs in structs i.e.
Struct1->Struct2.Struct3.Element.X = 10;
Struct1->Struct2.Struct3.Element.Y = 15;

No, C does not support this style of initialization or assignment.
If you want to access only a part of a structure, you need to express this explicitely.
EDIT:
You can get away with:
Variable = (foo){
.X = 15;
.Y = 20;
.Z = Variable.Z;
};
At least an optimizing compiler will just generate the operations for the changing elements. But it is more source than single assignments.

You can use the preprocessor to save your fingers (or copy/paste)...
struct {
int f1;
int f2;
struct {
int b1;
int b2;
int b3;
} bar;
} foo = {
1, 2, { 42, 43, 44 },
};
printf( "%d %d %d\n", foo.bar.b1, foo.bar.b2, foo.bar.b3 );
#define S foo.bar
S.b1 = 7;
S.b2 = 8;
printf( "%d %d %d\n", S.b1, S.b2, S.b3 );
#undef S

Related

C99 shorthand for operations on fields of a single struct variable?

Let's say I have this simple program:
#include <stdio.h>
typedef struct foo {
int bar;
int baz;
double qux;
} foo_t;
foo_t my_foo = {
.bar = 0,
.baz = 0,
.qux = 0,
};
int main() {
my_foo.bar = 100;
my_foo.baz = my_foo.bar/2 + 4;
my_foo.qux = my_foo.bar/3.0 + my_foo.baz/5.0;
printf("Hello, world %f!", my_foo.qux);
return 0;
}
Above, I'm using the "designated initializer style" { .bar = 0, ...} to initilize the struct variable, which I consider a kind of a shorthand.
I was wondering - is there some shorthand syntax, that would also allow for operations on fields of the same struct variable? For instance, instead of writing:
my_foo.bar = 100;
my_foo.baz = my_foo.bar/2 + 4;
my_foo.qux = my_foo.bar/3.0 + my_foo.baz/5.0;
... I could imagine a shorthand syntax like this (below pseudocode somewhat inspired by Python):
with(my_foo) {
.bar = 100;
.baz = .bar/2 + 4;
.qux = .bar/3.0 + .baz/5.0;
}
Is there something like this in C (C99, to be more specific)?
C has no such syntax. You need to specify the struct variable followed by the member name.
The closest you can come to this is to create pointers to each member and work with those.
int *bar = &foo.bar;
int *baz = &foo.baz;
double *qux = &foo.qux;
*bar = 100;
*baz = *bar/2 + 4;
*qux = *bar/3.0 + *baz/5.0;
Use the KISS principle. Meaning stick to simple, existing features in order to create readable, maintainable code:
void fooify (foo_t* dst, const foo_t* src)
{
int bar = src->bar;
int baz = src->baz;
double qux = src->qux;
bar += 100;
baz = bar/2 + 4;
qux = bar/3.0 + baz/5.0;
*dst = (foo_t)
{
.bar = bar,
.baz = baz,
.qux = qux,
};
}

C flexible array define with another type instead of malloc

the general usage of flexible array is to use malloc to define the flexible array. I'm trying to explore defining the flexible array with another struct. An example
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
typedef struct {
test_base_t base;
float data[3];
} test_t;
As I understand, flexible array needs to be defined at the end of a struct. And clangd will give the following warning. -Wgnu-variable-sized-type-not-at-end
I just wanted to ask if anybody has done this before and is it safe? Or is there a better way to define flexible array size without alloc?
You can then wrap the usage of the object in a macro to static assert ext.base.data == ext.data before casting and passing to a general API consumes test_base_t. This way you can have the memory required in compile instead of allocing.
Edit
There seem to be a confusion on how I wanted to consume it, here is an example to demonstrate
#define SUM_BASE(test) \
sum_base(&test->base); \
_Static_assert(test->data == test->base.data);
float sum_base(test_base_t *base)
{
float sum = 0;
for (size_t i = 0; i < base->data_size; i++)
{
sum += base->data[i];
}
return sum;
}
test_t test = { .base = { .data_size = 3, }, .data = { 1, 2, 3, }, };
SUM_BASE((&test));
You cannot create actual instances of test_base_t with an initialized array, but you can create compound literals with an initialized array of a specified length and cast their address as test_base_t pointers. The layout and alignment of both structures should be compatible, given that they have exactly the same types, save for the flexible array length.
Here is an example:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
#define TEST_ARRAY(n) (test_base_t*)&(struct { uint64_t header; \
size_t data_size; \
float data[n]; })
float sum_base(const test_base_t *p) {
float sum = 0.F;
for (size_t i = 0; i < p->data_size; i++) {
sum += p->data[i];
}
return sum;
}
void print_test(const test_base_t *p) {
printf("%"PRIu64" %zu { ", p->header, p->data_size);
if (p->data_size) {
printf("%g", p->data[0]);
for (size_t i = 1; i < p->data_size; i++) {
printf(" %g", p->data[i]);
}
}
printf(" } sum=%g\n", sum_base(p));
}
int main() {
test_base_t *p1 = TEST_ARRAY(1){.data_size = 1, .data = {1}};
test_base_t *p2 = TEST_ARRAY(2){.data_size = 2, .data = {1, 2}};
print_test(p1);
print_test(p2);
print_test(TEST_ARRAY(3){.data_size = 3, .data = {1, 2, 3}});
print_test(TEST_ARRAY(4){.data_size = 4, .data = {1, 3, 5, 7}});
return 0;
}
Here is another approach, perhaps closer to your expectations, using a union with a base member with the flexible type and a parametric instance type with the appropriate array size:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
/* parametric type template using C macros */
/* structures with a flexible array can be members of union types */
#define test_base_t(...) \
union { \
test_base_t base; \
struct { \
uint64_t header; \
size_t data_size; \
float data[__VA_ARGS__]; \
}; \
}
float sum_base(const test_base_t *p) {
float sum = 0.F;
for (size_t i = 0; i < p->data_size; i++) {
sum += p->data[i];
}
return sum;
}
void print_test(const test_base_t *p) {
printf("%"PRIu64" %zu { ", p->header, p->data_size);
if (p->data_size) {
printf("%g", p->data[0]);
for (size_t i = 1; i < p->data_size; i++) {
printf(" %g", p->data[i]);
}
}
printf(" } sum=%g\n", sum_base(p));
}
int main() {
test_base_t(1) t1 = { .data_size = 1, .data = {1} };
test_base_t(2) t2 = { .data_size = 2, .data = {1, 2} };
/* the print_test function can be called without casts */
print_test(&t1.base);
print_test(&t2.base);
print_test(&((test_base_t(3)){.data_size = 3, .data = {1, 2, 3}}).base);
print_test(&((test_base_t(4)){.data_size = 4, .data = {1, 3, 5, 7}}).base);
return 0;
}
C 2018 6.7.2.1 3 says of a structure containing a flexible array member:
… such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
Thus, the test_t type in the question violates this “shall” requirement, and C 2018 4 2 says that makes the behavior not defined by the C standard. A compiler could reject this code. If the compiler accepts it, the behavior of the program is not defined by the C standard.
As an example of what could go wrong (in that the C standard allows it), consider this code:
test_t test = { .base = { .data_size = 3, }, .data = { 1, 2, 3, }, };
printf("%g\n", test.base.data[0]);
Since test.base.data[0] was never assigned a value through that expression, and the standard does not define test.data to alias test.base.data, the compiler may assume the value of test.base.data[0] is uninitialized and hence unspecified, and this printf may use any value of the float type, even if test.base.data[0] and test.data[0] nominally refer to the same memory.
And in this code:
test_t test = { .base = { .data_size = 3, } };
for (int i = 0; i < 4; ++i)
test.base.data[i] = i+1;
test_t copy = test;
The compiler may assume that, since test.data was never initialized, it does not need to be copied to copy when initializing it from test.

cannot set values for variables in global structures?

struct ball{
int a;int b;
};
struct ball x;
x.a = 10; x.b = 20;
int main() {
x.a = 25; x.b = 50;
printf("%d %d\n",x.a,x.b);
}
Why won't this code work.Im trying to set struct ball x; as a global variable and then set the value of a and b.
This is the terminal error:
x.c:54:1: error: unknown type name 'x'
x.a = 10; x.b = 20;
^
x.c:54:2: error: expected identifier or '('
x.a = 10; x.b = 20;
^
The assignment
x.a = 10;
is an example of an expression statement. Expression statements (a statement which evaluates an expression, with an observable effect) are only permitted within functions.
It is possible to initialise a struct when defining a variable. For example;
struct ball x = {10, 20};
defines x (to be of type struct ball) and initialises its members (in order). Variable definitions that do initialisation like this are not restricted to only being used in a function body.
For standard C (1999 standard and later) it is also possible to use designated initialisers.
struct ball x = {.a = 10, .b = 20};
struct ball{
int a;int b;
};
struct ball x;
x.a = 10; x.b = 20; <-- Invalid to have assignment instruction outside of function body
int main()
{
...
return 0;
}
You intended to initialize the global variable. Yes, that is permitted and can be done as follows:
struct ball{
int a;int b;
};
struct ball x = {10, 20}; <-- struct global variable initialization
This works
struct ball{
int a;int b;
};
struct ball x;
//x.a = 10; x.b = 20;
int main() {
x.a = 25; x.b = 50;
printf("%d %d\n",x.a,x.b);
}
For global variable you are able to done the declaration part (struct ball x) and initialization part(int a = 0) only in outside of all functions.
Inside the functions only you are able to assign or modify the values for the global variables. So, only you are getting this error.

Why Can't We Initialize A Structure Multiple Times in C?

Why is this illegal in C? What is wrong with reinitializing p to a different posn? The same effect can be achieved by changing the field values individually so I don't understand why it can't be done in one step with p = {1, 2}.
struct posn {
int x;
int y;
};
int main() {
struct posn p = {3, 4};
p = {1, 2}; //Causes error
// must do p.x = 1; p.y = 2;
return 0;
}
That's the way the language is specified.
To stay somewhat consistent with C's general design, in order to allow p = {1, 2}, {1, 2} would have to be an expression. But of what type? It could be int[2], or struct { int a; short s; }, or a lot of other things.
With C99, a compound literal can be used, which explicitly mentions the type (and thereby solves the problem of how to determine the type), a parenthesized type-name followed by an initializer in {} brackets:
p = (struct posn){1, 2};
You may use a compound literal. For example
#include <stdio.h>
struct posn
{
int x;
int y;
};
int main(void)
{
struct posn p = { 3, 4 };
p = ( struct posn ){ 1, 2 };
printf( "p.x = %d, p.y = %d\n", p.x, p.y );
return 0;
}
The program output is
p.x = 1, p.y = 2
This works because structures opposite to arrays have copy assignment operator.
However you can enclose an array in structure and use the same trick to reassign arrays.
Here is an example
#include <stdio.h>
struct posn
{
int a[2];
};
int main(void)
{
struct posn p = { { 3, 4 } };
p = ( struct posn ){ { 1, 2 } };
printf( "p.a[0] = %d, p.a[1] = %d\n", p.a[0], p.a[1] );
return 0;
}
Thus it looks like std::array in C++.:)
That is not entirely true, you can't use the initializer list but you certainly can initialize or more precisely change the members of your struct whenever you want, try this
p.x = 1;
p.y = 2;
initializer lists can only be part of a declaration.

Adding (or doing any other math) every member of two same structs with less code

So, basically, I want to addify every member of first struct, with every member of second struct, and the structs are of same type. Like this:
struct Foo
{
int bar1;
int bar2;
int bar3;
int bar4;
int bar5;
}
Foo AddFoos(Foo foo1, Foo foo2)
{
Foo foo3;
foo3.bar1 = foo1.bar1 + foo2.bar1;
foo3.bar2 = foo1.bar2 + foo2.bar2;
foo3.bar3 = foo1.bar3 + foo2.bar3;
foo3.bar4 = foo1.bar4 + foo2.bar4;
foo3.bar5 = foo1.bar5 + foo2.bar5;
return foo3;
}
However, when structs keep getting bigger, this way is weird. Is there any way to do it with less lines of code? And preferably without advanced pointer magic?
Use an array instead and a for loop to add the numbers:
struct Foo
{
int bars[100];
};
for (i=0;i<100;i++)
{
foo3.bars[i]=foo1.bars[i]+foo2.bars[i];
}
You can malloc if the array size is unknown at compile time and change the struct to this and then malloc for all three Foo variables.
struct Foo
{
int *bars;
};
You want the comfort of named fields (bar1 .. barN) and something like an array you can loop over to automate the operations. First we define the struct (a dense representation of the fields in memory):
struct VectorFields {
int a;
int b;
int c;
};
Then we need to get to know the number of the fields used in that struct:
#define VECTOR_FIELDS_LEN (sizeof(struct VectorFields) / sizeof(int))
(In C++ you could use some template magic foo, here we just use the preprocessor as a simpler variant). Next, we combine the struct VectorFields with an array of int so both match in size, also known as union:
union Vector {
struct VectorFields fields;
int raw[VECTOR_FIELD_LEN];
};
(Note: VECTOR_FIELD_LEN must be a known constant value to the compiler, hence the preprocessor thingy before.) You are now able to access the data either by it's name (.fields.a) or by an index (.raw[0]). So, let's write the function which adds the Vector together:
void vector_add(union Vector* result, union Vector* a, union Vector* b) {
int i;
for (i = 0; i < TUPLE_LEN; i++) {
result->raw[i] = a->raw[i] + b->raw[i];
}
}
You might use it like this then:
#include <stdio.h>
int main() {
union Vector a = { .fields = { 1, 2, 3 } };
union Vector b = { .fields = { 4, 5, 6 } };
union Vector sum;
vector_add(&sum, &a, &b);
printf("%d %d %d\n", sum.fields.a, sum.fields.b, sum.fields.c);
return 0;
}
Depending on what you call "advanced pointer magic", you can use the following moderately magical code:
Foo AddFoos(Foo foo1, Foo foo2)
{
Foo foo3;
int *pointer1 = &foo1.bar1; // first field here
int *pointer2 = &foo2.bar1; // first field here
int *pointer3 = &foo3.bar1; // first field here
while (pointer3 <= &foo3.bar5) // last field here
{
*pointer3++ = *pointer1++ + *pointer2++;
}
return foo3;
}
When you change the definition of Foo, just update the names of the first and last field.
This will only work when all fields are of the same type.
If you have only ints you can use an array
struct Foo {
int bar[5];
};
Foo AddFoos(Foo f1, Foo f2)
{
Foo f3;
int i;
for (i = 0; i < 5; ++i)
f3.bar[i] = f1.bar[i] + f2.bar[i];
return f3;
}

Resources