csyntaxinitializeranonymous-struct

Correct syntax for whole array initializaition


Why is the following an error and what is the correct syntax?

struct a {
    int b[4];
};

int c[4];
struct a a = {.b = &c};

Shouldn't a.b be of type int * or int[], why is it of type int?

(Note, that the declaration of struct a can't be changed.)


Solution

  • The C language is a bit weird since for historical reasons it does not allow initialization or assignment between two arrays. That's just how the language is defined.

    C does however allow structs to be initialized/assigned from other structs of the same type. Even if they happen to contain an array. So you could do this:

    struct a c = { .b = {1,2,3,4} };
    ...
    struct a a = c;
    

    Or otherwise skip initialization and use run-time assignment instead. Since we're dealing with arrays we can't use = but have to use memcpy:

    int c[4] = {1,2,3,4};
    struct a a;
    memcpy(a.b, c, sizeof(a.b));
    

    As for the reason for the peculiar compiler error:

    warning: initialization of 'int' from 'int (*)[4]' makes integer from pointer without a cast [-Wint-conversion]

    Initialization of arrays (or structs) is done by the compiler internally keeping track on the current object to initialize. When we type in a designated initializer .b, the compiler sets the current object to be initialized to the first item b[0] in the array b. And then expects a number of initializers with type int from there on. For each int we hand it in the initializer list, it will automatically shift current initialized object to the next one in the list, b[1], b[2] and so on.

    If written properly that would look like .b = {1,2,3,4} but the braces are actually optional. What matters is the compiler keeping track of the current object. We could as well write sloppy code like .b = 1,2,3,4. Very bad practice but valid C.

    Anyway, since the compiler expects an int but is given a pointer to array with &c, it raises a constraint violation diagnostic message. It expected an int but got a int (*)[4] and that is invalid C.

    .b = something is fine as far as the syntax is concerned, the types just didn't match in case of .b = &c. The types are regulated by the constraints of the assignment operator. A compiler must give a diagnostic message whenever the code violates either the C syntax or the C constraints.