To answer your title question, you can't in the form you've written it in, but you can with the help of a union:
struct A {
int a;
union {
char b[16];
struct { char b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15; }
};
int c;
};
Now you can assign and use it like this:
const A test = {
.a = 1,
.b0 = 'a', .b1 = 'b', .b2 = 'c', .b3 = 'd', .b4 = 'e', .b5 = 'f', .b6 = 'g', .b7 = 'h', .b8 = 'i', .b9 = 'j', .b10 = 'k', .b11 ='l', .b12 ='m', .b13 ='n', .b14 ='o', .b15 = 'p',
.c = 255
};
printf("The final b is >%c<.\n", test.b[15]); // prints: The final b is >p<.
This works because of the flat layout of a fixed-size array in a struct (that others have mentioned), and because unions (in this case an anonymous union) let you access the same memory location via differing types with different identifiers. Essentially, you're just setting up a typecast ahead of time here.