Home > other >  Undefined Behavior in Unions with Standard Layout structs
Undefined Behavior in Unions with Standard Layout structs

Time:10-18

Take the following code

union vec
{
    struct
    {
        float x, y, z;
    };

    float data[3];

    constexpr vec() : data{} {}
};

constexpr vec make_vec(float x, float y, float z)
{
    vec res;
    res.data[0] = x;
    res.data[1] = y;
    res.z = z;
    return res;
}

int main()
{
    constexpr vec out = make_vec(0, 1, 2);
    std::cout << out.z << '\n';
}

I make use of constexpr here to determine whether the code is undefined behavior or not, as the undefined behavior will cause a compilation error.

§9.2/19:

If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them.

From this, I would assume that everything in the code would be defined behavior.

Compiling with g main.cpp -o out -std=c 17, I get the message error: change of the active member of a union from 'vec::data' to 'vec::<anonymous>'.

I thought that to comply with the standard, I might've had to change it to this--

union vec
{
    struct
    {
        float x, y, z;
    };

    struct
    {
        float data[3];
    };

    constexpr vec() : data{} {}
};

But I get the same error.

Is this truly undefined behavior? Is there perhaps another part of the standard that I've missed, or am I simply misinterpreting the standard?

CodePudding user response:

Yes, this is UB.

After you write to float data[3]; part of the union, you are not allowed to read the struct { float x, y, z; };

This is as simple as that.

that share a common initial sequence

Doesn't cover these two, as an array is not the same as a float followed by another float.

  • Related