Reputation: 991
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
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
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