Home > Back-end >  Initializing constant array of type struct
Initializing constant array of type struct

Time:08-06

I am unable to initialize a constant array of a custom type. Following is the code:

union chk {
    struct{
        int a : 4;
        int b : 12;
    }stNative;
    int nVal;
};

const chk obj[2] = {0x1234, 0x6789};

int main() {
    
    cout << obj[0].nVal<<endl;
}

On Executing the above code, I get some random values. I am not able to understand the reason this is happening and how can it be fixed. O/P of the above code is : 30868

CodePudding user response:

Initialization in declaration assigns the values to the first union member stNative, that is a struct with two values. You have provided the values for the first struct member a with overflow. This small update will initialize both the struct members.

#include <iostream>
using namespace std;

union chk {
    struct{
        int a : 4;
        int b : 12;
    }stNative;
    int nVal;
};

const chk obj[2] = {{0x1, 0x234}, {0x6, 0x789}};

int main() {
    // Undefined behaviour bellow while reading nVal
    cout << std::hex << obj[0].nVal<<endl;
}
// Output: 2341

Type punning is not allowed in C . If you initialize the union member stNative, then should read it only, reading nVal is not allowed. Use std::bit_cast or memcpy for type punning.

CodePudding user response:

In C 20, you can do this to initialize that particular member explicitly:

union chk {
    struct {
        int a : 4;
        int b : 12;
    } stNative;
    int nVal;
};

int main() {
    const chk obj[2] = {{.nVal = 0x1234}, {.nVal = 0x6789}};
}

CodePudding user response:

I'd like to add that in this particular case you were victimised by brace elision of embedded aggregate type:

The braces around the nested initializer lists may be elided (omitted), in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, and the subsequent initializer clauses are used to initialize the following members of the object.

So while you think that you initialise the int nVal property of the union, you in fact initialise the struct stNative. The reason for that is (as pointed out in the 273Ks answer) because the struct member comes first in the declaration of the union.

If brace ellision was not a thing, you array initialisation would have to look something like this (or otherwise would be considered ill-formed):

const chk obj[2] = {{ 0x1234, 0x6789 }};
  • Related