Matias Chara
Matias Chara

Reputation: 991

Is there any way to use type-punning in the c-union-style with c++?

Say we have the following union:

union Color{
    int rgba;//assuming 32 bit int
    struct{
        unsigned char r;
        unsigned char g;
        unsigned char b;
        unsigned char a;
    }ColorComp;
};

It is indeed undefined behaviour (only in c++, not in c) to access an inactive element of the union(setting say rgba and trying to access r). Is there any way to have this type of behaviour(NOTE: must be well-defined by standard) where types or combinations of types can read/write to the same memory locations as other different types-i.e type-punning- in c++?

Upvotes: 1

Views: 139

Answers (2)

doug
doug

Reputation: 4299

Here's a way to make c type union type punning work in c++20. You can use std::bit_cast to change the alive union member. This can also be done at compile time for things like an endian check.

#include <cstdint>
#include <iostream>
#include <bit>

union Color {
    int rgba;//assuming 32 bit int
    struct RGBA_Char {
        unsigned char r;
        unsigned char g;
        unsigned char b;
        unsigned char a;
    }ColorComp;
    constexpr void rgba_alive() { rgba = std::bit_cast<int>(ColorComp); }
    constexpr void ColorComp_alive() { ColorComp = std::bit_cast<RGBA_Char>(rgba); }
};


int main()
{
    Color color;
    color.rgba = 1;
    color.ColorComp_alive();
    std::cout << 0+color.ColorComp.r << '\n';   // outputs 1 if little endian
}

Upvotes: 0

eerorika
eerorika

Reputation: 238371

Yes, there is a way. Copy the bytes onto an object of type that you want to read the bytes as. There is a standard function for this: memcpy.

Example:

struct Color{
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
};

static_assert(sizeof(Color) == sizeof(std::int32_t));
std::int32_t rgba = some_value;
Color c;
std::memcpy(&c, &rgba, sizeof c);

Upvotes: 3

Related Questions