Why can't a defined, fix-sized array be assigned using a compound literal?

Viewed 107

Why is it so that a struct can be assigned after defining it using a compound literal (case b) in sample code), while an array cannot (case c))?

I understand that case a) does not work as at that point compiler has no clue of the memory layout on the rhs of the assignment. It could be a cast from any type. But going with this line, in my mind case c) is a perfectly well-defined situation.

typedef struct MyStruct {
  int a, b, c;
} MyStruct_t;

void function(void) {
  MyStruct_t st;
  int arr[3];

  // a) Invalid
  st = {.a=1, .b=2, .c=3};
  // b) Valid since C90
  st = (MyStruct_t){.a=1, .b=2, .c=3};
  // c) Invalid
  arr = (int[3]){[0]=1, [1]=2, [2]=3};
}

Edit: I am aware that I cannot assign to an array - it's how C's been designed. I could use memcpy or just assign values individually.

After reading the comments and answers below, I guess now my question breaks down to the forever-debated conundrum of why you can't assign to arrays.

What's even more puzzling as suggested by this post and M.M's comment below is that the following assignments are perfectly valid (sure, it breaks strict aliasing rules). You can just wrap an array in a struct and do some nasty casting to mimic an assignable array.

typedef struct Arr3 {
  int a[3];
} Arr3_t;

void function(void) {
  Arr3_t a; 
  int arr[3];

  a = (Arr3_t){{1, 2, 3}};
  *(Arr3_t*)arr = a;
  *(Arr3_t*)arr = (Arr3_t){{4, 5, 6}};
}

So then what's stopping developers to include a feature like this to, say C22(?)

2 Answers

C does not have assignment of arrays, at all. That is, where array has any array type, array = /* something here */ is invalid regardless of the contents of "something here". Whether it's a compound literal (which you seem to have confused with designated initializer, a completely different concept) is irrelevant. array1 = array2 would be just as invalid.

As to why it's invalid, at some level that's a question of the motivations/rationale of the C language and its design and unanswerable. However, mechanically, arrays in any context except the operand of sizeof or the operand of & "decay" to pointers to their first element. So in the case of:

arr = (int[3]){[0]=1, [1]=2, [2]=3};

you are attempting to assign pointer to the first element of the compound literal array to a non-lvalue (the rvalue produced when arr decays). And of course that is nonsense.

A compound array literal can be used anywhere that an actual array variable can be used. Since you can't assign one array to another array, it's also not valid to assign a compound literal to an array.

Since you can copy arrays using memcpy(), you could write:

memcpy(arr, (int[3]){[0]=1, [1]=2, [2]=3}, sizeof(arr));

Just like the array variable, the array literal decays to a pointer to its first element.

Compound struct literals can also be used in place of an actual struct variable. But structs can be assign to each other, so it's valid to assign a compound struct literal to a struct variable.

That's the difference between the two cases.

Related