0

Consider the piece of declaration:

struct my_cool_struc {
   int field_x;
   int field_Y;
   int field_z;
};

#define MY_COOL_MACRO(x,y,z) \
  { \
    .field_x = (x), \
    .field_y = (y), \
    .field_z = (z), \
  }

static const struct my_cool_struc why[] = {
  MY_COOL_MACRO(1,2,3),
  MY_COOL_MACRO(6,5,4),
  MY_COOL_MACRO(7,8,9),
  {}
};

static int my_cool_func(...)
{
   struct my_cool_struc p[10];
   int a1, a2, a3;
   unsigned int index = 0;
...
   p[index++] = MY_COOL_MACRO(a1, a2, a3);
...
   return 0;
}

While in the why assignment everything works fine, compiler can's build the function, fails on syntax parser.

The following fixes the issue:

- { \
+ (struct my_cool_struc) { \

or

- p[index++] = MY_COOL_MACRO(a1, a2, a3);
+ p[index++] = (struct my_cool_struc)MY_COOL_MACRO(a1, a2, a3);

Compiler is GCC (different versions) on Linux.

JJJ
  • 32,902
  • 20
  • 89
  • 102
0andriy
  • 4,183
  • 1
  • 24
  • 37
  • 1
    Not 100% sure, but i think that you second version is a compound literal (http://en.cppreference.com/w/c/language/compound_literal) while the fist one is just invalid code. – Sister Fister Jan 25 '18 at 13:20
  • 2
    You get syntax errors because that's invalid syntax for assigning to a structure. Initialization and assignment are two very different things. – Some programmer dude Jan 25 '18 at 13:20
  • @SisterFister, first case works nice w/o any errors. – 0andriy Jan 25 '18 at 13:22
  • @Someprogrammerdude, any pointers to documentation? Moreover, the question is why the first case is okay, while second one fails. In both cases lvalue has a defined type. – 0andriy Jan 25 '18 at 13:22
  • With first and second I meant the vesions before and after your patch. – Sister Fister Jan 25 '18 at 13:23
  • @SisterFister, ah, okay, see my last comment to Dude. – 0andriy Jan 25 '18 at 13:23
  • 3
    E.g. `{.a = x, .b = y}` is not a structure, it's an initialization list. `(struct some_struct){.a = x, .b = y}` on the other hand *is* a structure, it's a [*compound literal*](http://en.cppreference.com/w/c/language/compound_literal). See [this C language reference](http://en.cppreference.com/w/c/language) for more information, or [read some good books](https://stackoverflow.com/a/562377/440558). – Some programmer dude Jan 25 '18 at 13:26
  • @Someprogrammerdude, thanks, got it. – 0andriy Jan 25 '18 at 13:29

1 Answers1

4

MY_COOL_MACRO when used in the declaration, is using designated initializers, which is a feature only existing during initialization. They cannot be used during assignment.

The reason why (struct my_cool_struc)MY_COOL_MACRO fixes the problem during assignment, is because it is not a cast at all. Rather, it is creating a temporary, unnamed object known as compound literal:

(struct my_cool_struc){ .field_x = (x), .field_y = (y), .field_z = (z) }

And since you are creating an object, the part between { } is an initializer list, where you can use designated initializers.

You then assign the compound literal to your array item in run-time, which is perfectly fine.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Yep, I have got it. How does the fix I posted (variant 1) affect initialization of constant `why`? – 0andriy Jan 25 '18 at 13:46
  • 1
    @0andriy Not at all, it is redundant and will get optimized away. It is basically the same as writing `int x = (int){ 5 };` rather than just `int x = 5;`. The compound literal in this case adds nothing and makes the code harder to read. – Lundin Jan 25 '18 at 14:21