Search code examples
cpointersinitializationunions

How to use pointers in an union in C?


I want to initialize this structure:

typedef struct
{
    int num;
    union 
    {
        const char** ppStrList;
        const char* pStr;
    };
    union
    {
        int num1;
        int num2;
    };
} tMyStruct;

If I try to initialize this structure when I declare the variable I get an error: For example;

const char *gpStr = "str";

const char *gpStrList[2] =
{
    {"str1"},
    {"str2"}
};

tMyStruct myStruct[2] = 
{
    {0,{gpStrList},{3}},
    {1,{gpStr},{4}}
};

The variable gpStr can´t be used to initialize the structure

But it can be initialized inside of a function without problem:

int main(int argc, char *argv[])
{
    myStruct[0].num = 0;
    myStruct[0].ppStrList = gpStrList;
    myStruct[0].num1 = 3;

    myStruct[1].num = 0;
    myStruct[1].pStr = gpStr;
    myStruct[1].num2 = 3;
}

Why the structure can't be initialized when it is declared?

I think the union has a special behavior because if I don’t use an union the problem doesn’t exist. For example:

typedef struct
{
    int num;
    union /* Union to contain ppStrList and pStr pointers */
    {
        const char** ppStrList;
        const char* pStr;
    };
    union
    {
        int num1;
        int num2;
    };
} tMyStruct1;


typedef struct
{
    int num;
    /* I don´t use an union */
    const char** ppStrList;
    const char* pStr;

    union
    {
        int num1;
        int num2;
    };
} tMyStruct2;

const char gStr[] = "str";

const char *gpStrList[2] = 
{
    {"str1"},
    {"str2"}
};

tMyStruct1 myStruct1[2] = /* Structure with union inside */
{

    {0,{gpStrList},{3}},
    {1,{gStr},{4}}  /* <--- Error here if I use gStr address with union */
};

tMyStruct2 myStruct2[2] = /* Structure without union inside */
{
    {0,gpStrList,NULL,{3}},
    {1,NULL,gStr,{4}} /* <--- No poblem here if I use gStr address */
};

Solution

  • Variables initialized at file scope (whether static or not) and variables initialized at block scope with static duration can only be initialized with constants. Automatic variables (necessarily at block scope) can be initialized with expressions.

    Also, when a union is initialized, the initializer must match the first member unless a designated initializer is used. With C99 or later, you could write:

    typedef struct
    {
        int num;
        union 
        {
            const char** ppStrList;
            const char* pStr;
        };
        union
        {
            int num1;
            int num2;
        };
    } tMyStruct;
    
    const char gpStr[] = "str";
    
    const char *gpStrList[2] =
    {
        "str1",
        "str2"
    };
    
    tMyStruct myStruct[2] = 
    {
        { .num = 0, { .ppStrList = gpStrList }, { .num1 = 3 } },
        { .num = 1, { .pStr      = gpStr     }, { .num2 = 4 } },
    };
    

    Note the tweaked type for gpStr. You don't have to use the designated initializers for all the elements, but consistency suggests you probably should. Also note that a union of two differently named int members is modestly pointless. The different elements of a union should normally be of different types.