Search code examples
cstructinitializationliteralscompound-literals

Why is an explicit cast necessary in the following struct definition


With struct initialization via a compound literal, it will do the casting itself. For example:

struct movie {
    char title[50];
    int year;
};
typedef struct movie Item;

typedef struct node {
    Item        item;
    struct node *next;
} Node;

typedef struct linkedlist {
    Node   *head;
    size_t size;
} LinkedList;
LinkedList movies2 = {
    .head=&(Node){{"Avatar", 2010}, NULL},
    .size=1
};

However, if I separate the definition, I have to add in an explicit cast:

LinkedList movies2;
movies2 = (LinkedList) {
    .head=&(Node){{"Avatar", 2010}, NULL},
    .size=1
};

Code: https://godbolt.org/z/dG8nMh

And if I leave out the (cast_type) in the second one I will get an error along the lines of error: expected expression before ‘{’ token. Why is this so?

That is, why does the initialization not need the cast but the other definition does? My thought was the second version should be able to resolve itself without the explicit cast but obviously that is incorrect.


Solution

  • In the both cases you are using compound literals.

    In the first case in the declaration

    LinkedList movies2 = {
        .head=&(Node){{"Avatar", 2010}, NULL},
        .size=1
    };
    

    you are using the compound literal (Node){{"Avatar", 2010}, NULL} of the type Node in the initializer list the address of which is used as an initializer for the data member head of the structure LinkedList.

    In the second case you at first created an object of the type LimkedList

    LinkedList movies2;
    

    and then you are using the assignment operator to the created object with the compound literal of the type LinkedList

    (LinkedList) {
        .head=&(Node){{"Avatar", 2010}, NULL},
        .size=1
    }
    

    that is

    movies2 = (LinkedList) {
        .head=&(Node){{"Avatar", 2010}, NULL},
        .size=1
    };
    

    That is there are no any casting. There are used two different compound literals. One of the type Node and other of the type LinkedList.

    To make it clear. Consider a simple example

    int x = { 10 };
    

    in the declaration above the variable x is initialized by the integer constant 10.

    You can write also the following way

    int tmp = { 10 };
    int x;
    x = tmp;
    

    Here there is created an intermediate variable to initialize the variable x. A compound literal in fact is an unnamed object. The code above may be rewritten like

    int x;
    x = ( int ){ 10 }; 
    

    Here there is no any casting. This expression ( int ){ 10 } creates an unnamed object of the type int that is initialized by the integer constant 10. And this newly created unnamed object is assigned to the variable x.

    See also the following question What are the advantages of using “{}” for casting in C Language?