#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
enum class OrderFlags : uint16_t {
None = 0,
BuySide = 1,
UpdateVolume = 2,
UpdatePrice = 4,
Market = 8,
Float = 16,
Aggressive = 32,
};
struct OrderFlagsBitField {
uint8_t side : 1;
uint8_t update_volume : 1;
uint8_t update_price : 1;
uint8_t market_order : 1;
uint8_t float_order : 1;
uint8_t aggressive : 1;
uint16_t reserved : 10;
};
static_assert(sizeof(OrderFlagsBitField) == 2);
struct Order {
int order_id;
union {
OrderFlags flags;
OrderFlagsBitField flags_bf;
};
};
int main()
{
Order order1;
order1.order_id = 123;
uint16_t value = 1 + 2 + 8 + 32;
memcpy(&order1.flags, &value, sizeof(value));
Order order2 = order1;
cout << int(order2.flags_bf.side) << " " << int(order2.flags_bf.update_volume) << " " << int(order2.flags_bf.update_price) << " "
<< int(order2.flags_bf.market_order) << " " << int(order2.flags_bf.float_order) << " " << int(order2.flags_bf.aggressive) << "\n";
return 0;
}
I have a code like above. value
represents a flag that can contain multiple OrderFlags
value. Basically, I want to serialize a uint16_t
into a Order
object with this union.
Is this code safe or not? For this case, the output should be 1 1 0 1 0 1
, even if I write order1
object into a file, then read-as-byte from that file again into order2
.
It's undefined behavior. Handle each flag in the bit field instead. Such as:
int bf2int(BitFieldFlag flag)
{
int res = 0;
if (flag.attribute1) res |= 1 << 0;
if (flag.attribute2) res |= 1 << 1;
// ...
return res;
}
void int2bf(BitFieldFlag &flag, int flag_int)
{
memset(&flag, 0, sizeof(flag));
if ((flag_int >> 0) & 1) flag.attribute1 = 1;
if ((flag_int >> 1) & 1) flag.attribute2 = 1;
// ...
}