首页
学习
活动
专区
圈层
工具
发布

双关式
EN

Stack Overflow用户
提问于 2022-04-06 14:52:32
回答 1查看 132关注 0票数 2

我正在维护一个旧的代码库,即使用整数类型与位字段结构的联合进行类型双关。我的编译器是VS2017。例如,代码类似于以下内容:

代码语言:javascript
复制
struct FlagsType
{
    unsigned flag0 : 1;
    unsigned flag1 : 1;
    unsigned flag2 : 1;
};

union FlagsTypeUnion
{
    unsigned  flagsAsInt;
    FlagsType flags;
};

bool isBitSet(unsigned flagNum, FlagsTypeUnion flags)
{
    return ((1u << flagNum) & flags.flagsAsInt);
}

此代码存在许多未定义的行为问题。也就是说,类型双关是否是定义的行为引起了激烈的争论,但最重要的是,打包位字段的实现是实现定义的。为了解决这些问题,我想添加静态断言语句来验证VS实现是否允许使用这种方法。但是,当我试图添加以下代码时,我会得到错误的C2131:常量。

代码语言:javascript
复制
union FlagsTypeUnion
{
    unsigned  flagsAsInt;
    FlagsType flags;
    constexpr FlagsTypeUnion(unsigned const f = 0) : flagsAsInt{ f } {}
};

static_assert(FlagsTypeUnion{ 1 }.flags.flag0,
    "The code currently assumes bit-fields are packed from LSB to MSB");

是否有任何方法添加编译时检查来验证类型双关和位打包代码的工作方式与运行时代码假设的相同?不幸的是,这段代码分散在整个代码库中,因此更改结构是不可行的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-06 16:03:58

您可以使用std::bit_cast (C++20):

代码语言:javascript
复制
struct FlagsType
{
    unsigned flag0 : 1;
    unsigned flag1 : 1;
    unsigned flag2 : 1;
    unsigned padding : 32 - 3; // Needed for gcc
};

static_assert(std::is_trivially_constructible_v<FlagsType>);

constexpr FlagsType makeFlagsType(bool flag0, bool flag1, bool flag2)
{
    FlagsType res{};

    res.flag0 = flag0;
    res.flag1 = flag1;
    res.flag2 = flag2;
    return res;
}

static_assert(std::bit_cast<unsigned>(makeFlagsType(true, false, false)) == 1);

演示

  • 不过,clang并不支持这一点。
  • gcc需要显式地添加用于constexpr检查的填充位。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71768987

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档