cstructrvalue

C struct assignment by unnamed struct initialized by member-wise list, syntax candy or unintentional memory overhead?


Prior statement: I'm a programmer long coding in C++ and Python, so kindly pardon and teach if my question looks too silly due to my thinking of C in an OOD way. Also I've tried lot searching on different forums but found no suitable answer, so posted it here.


I am trying to initialize a struct, and learned that I can do it member-wise as below by { .next = NULL, .val = val } in the put function:

typedef struct HashNode HashNode;
struct HashNode
{
    struct HashNode *next;
    int val;
};

HashNode **_arr = NULL;

int put( int val )
{
    int index = val % N;
    HashNode *node = _arr[index];
    while ( node ) {
        node = node->next;
    }
    node = (HashNode*)malloc(sizeof(HashNode*));
    *node = (HashNode){ .next = NULL, .val = val }; 
    return 0;
}

But I wonder what actually happens here? Do I effectively created an unnamed rvalue of type HashNode on stack, and then effectively member-wise copied it to the *node? Or does it work only as a syntax sugar just like C++ constructor by initialization lists?


Solution

  • The code should create an unnamed value on the stack and copy it over, but in reality it is optimised away.

    I've used the following to test with gcc with no optimisation:

    #include <stdlib.h>
    
    struct a
    {
        int aa;
        int ab;
        int ac;
        int ad;
        int ae;
    };
    
    int main(int argc, char *argv[])
    {
        volatile struct a *ptr = malloc(sizeof(struct a));
        *ptr = (struct a){.aa = 1, .ab = 2, .ac = 3, .ad = 4, .ae = 5};
        free(ptr);
        return 0;
    }
    

    With the volatile keyword, the generated assembly copies from the stack. Without it, the values are written directly to *ptr.