如何解决如何使用组成排序键的位域而不落入UB?
假设我要具有以下位域:
struct SortingKey {
uint8_t a: 2;
uint8_t b: 4;
uint8_t c: 2;
}
要使用简单的整数比较,我可能需要像这样将其包装为一个并并使用value
进行排序:
union UnionSortKey {
SortingKey key;
uint8_t value;
}
但是,在C ++中,读取不活动的工会成员是未定义行为。 如何保证我不会陷入UB,而是保持简单的整数比较?
解决方法
您不能将并集类型的联合使用
在C ++ 20中,您可以使用默认的operator <=>
struct SortingKey {
uint8_t a: 2;
uint8_t b: 4;
uint8_t c: 2;
auto operator <=>(const SortingKey&) const = default;
};
之前,您必须手动提供转换/比较:
bool compare(SortingKey lhs,SortingKey rhs)
{
if (lhs.a != rhs.a) return lhs.a < rhs.a;
if (lhs.b != rhs.b) return lhs.b < rhs.b;
return lhs.c < rhs.c;
}
或
bool compare(SortingKey lhs,SortingKey rhs)
{
auto to_u8 = [](SortingKey s) -> std::uint8_t{ return s.c << 6 | s.b << 2 | s.a; };
return to_u8(lhs) < to_u8(rhs);
}
如果您很幸运(位域是特定于实现的,那么...),您的编译器可以对基础类型进行简单的比较。
(c按“正确”的顺序成功完成了优化)。
或者,如果您没有填充位/字节,则可以使用memcpy
/ memcmp
(成功优化)
bool compare(SortingKey lhs,SortingKey rhs)
{
auto to_u8 = [](SortingKey s) -> std::uint8_t{
std::uint8_t c; memcpy(&c,&s,1); return c;
};
return to_u8(lhs) < to_u8(rhs);
}
或
bool compare(SortingKey lhs,SortingKey rhs)
{
return memcmp(&lhs,&rhs,1) < 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。