如果我没记错的话,写入FastKey::key
然后从FastKey::keyValue
读取将是未定义的行为:
struct Key {
std::array<uint8_t, 6> MACAddress;
uint16_t EtherType;
};
union FastKey {
Key key;
uint64_t keyValue;
};
但是,有人告诉我,如果我将char数组添加到union中,那么UB将被清除:
union FastKey {
Key key;
uint64_t keyValue;
char fixUB[sizeof(Key)];
};
这是真的吗?
像往常一样,我的理解是错误的。根据我收集的新信息,我认为我可以将密钥作为uint64_t
这样的值获取:
struct Key {
std::array<uint8_t, 6> MACAddress;
uint16_t EtherType;
};
union FastKey {
Key key;
unsigned char data[sizeof(Key)];
};
inline uint64_t GetKeyValue(FastKey fastKey)
{
uint64_t key = 0;
key |= size_t(fastKey.data[0]) << 56;
key |= size_t(fastKey.data[1]) << 48;
key |= size_t(fastKey.data[2]) << 40;
key |= size_t(fastKey.data[3]) << 32;
key |= size_t(fastKey.data[4]) << 24;
key |= size_t(fastKey.data[5]) << 16;
key |= size_t(fastKey.data[6]) << 8;
key |= size_t(fastKey.data[7]) << 0;
return key;
}
我怀疑这与原始版本一样快。随意纠正我。
@Steve Jessop我实现了一个quick benchmark来测试memcpy与我的解决方案的性能。我不是基准测试专家,因此代码中可能存在愚蠢的错误导致错误的结果。但是,如果代码是正确的,那么memcpy似乎要慢得多。
注意:似乎基准测试是错误的,因为计算快速键时间的时间总是为零。我会看看是否可以修复它。
答案 0 :(得分:4)
不,如果你有一个uint64_t
对象,那么阅读Key
仍有UB。 UB不是读char
,因为别名规则中char
有例外。添加数组不会将异常传播到其他类型。
编辑中的版本似乎很好(虽然我使用unsigned char
),但现在它比使用reinterpret_cast
到Key*
的{{1}}更复杂或unsigned char*
。