【问题标题】:Portable way to assign maximum value to a bitfield将最大值分配给位域的便携式方法
【发布时间】:2016-03-18 11:56:59
【问题描述】:

假设我有一个这样的位域:

struct SomeStruct {
    uint32_t first : 12;
    uint32_t second : 2;
    uint32_t third : 18;
};

SomeStruct obj;

我要分配

obj.second = 3;  // Actually, the maximum allowed value

实现此目的的可移植方式是什么? 我也不想明确使用已知的位域宽度。

我使用的代码

obj.second = std::numeric_limits<uint32_t>::max()

但是-Wbitfield-constant-conversion 发出警告,cpp reference states:

位域的以下属性是实现定义的 由分配或初始化位域产生的值 值超出范围,或将位字段递增超出其范围。

那么分配-1 或numeric_limits&lt;uint32_t&gt;::max() 真的是可移植的还是有其他方法?

【问题讨论】:

  • @NathanOliver,所以你是否暗示我的问题的答案是“这不可能?”
  • 好吧,如果您想获得以位为单位的大小来计算最大值,那么可以。这取决于你想做什么。这就是为什么我先选择相关的。
  • 我想指定一个最大值。链接的问题意味着通过首先获取大小是不可能的,好的。有趣的一点是,虽然可以通过获取最大值来获取位大小:)

标签: c++ portability bit-fields


【解决方案1】:

由于字段未签名,因此工作很简单:

obj.second = -1;

无符号算术可以很好地环绕,即使对于位域也是如此。

【讨论】:

  • 这是最佳答案
  • 当我设法找到这个en.cppreference.com/w/cpp/language/bit_field 时,您能否详细说明一下标准/其他可靠来源的链接,并指出“位字段的以下属性是实现定义的使用超出范围的值分配或初始化位字段,或将位字段递增超出其范围而产生的值。'
  • @unkulunkulu 我在 C++ 标准中看不到任何与该引用相对应的文本。位域部分中没有任何内容对其在超出范围转换时的行为进行例外处理;。所以我认为 [conv.integral] 适用,这与其他整数类型的行为相同:超出范围转换为无符号环绕,超出范围转换为有符号是实现定义的。
  • 好的,那么我真的应该问一个关于 clang 警告的单独问题并接受这个答案。谢谢!
  • 或者实际上这只是同一个问题。我现在很困惑。带有 -Wbitfield-constant-conversion 的 Clang 只会在尝试执行此任务时给我警告/错误。
【解决方案2】:

如果你有两个位,最大值是 22-1。获得该值的一种简单方法是将1 向左移动两步(给您 22)并减去 1。

所以 2 位的最大值是 (1U &lt;&lt; 2) - 1。

它在所有 C 编译器之间是可移植的,并且编译器将能够优化操作,因此分配只针对结果值。

【讨论】:

  • 好的,可移植的,但我希望这个分配是稳定的,并且在位域宽度发生变化时工作。我会把这个添加到问题中
【解决方案3】:

CWG 1816 明确表示分配一个位域无法表示的值,结果值是实现定义的。

恐怕,我不知道任何可移植的方式来实现你想要的。

【讨论】:

    【解决方案4】:

    最好的方法是分配它-1/-1L/~0/~0L 或INT_MAX/LONG_MAX。

    但是这段代码依赖于当今计算机中整数的表示方式。这在任何地方都有效,但从 C 标准规范正式开始是不可移植的。

    【讨论】:

    • ~0 依赖于 2 的补码表示
    • @M.M:没错。但是当为较小的类型分配一个数字时,C 标准说它使用模数。换句话说,如果这个数字不是 2 的幂,就会产生一些奇怪的数字。虽然目前所有的软件都非常依赖这个......
    【解决方案5】:

    对于无符号整数类型:

    unsigned char max = ~0;
    

    在英语中,零补码将所有位设置为 1,这是该类型的最大无符号值。

    当您使用位域时,这种简单的方法可能不适合您。如果您使用的是:

    struct SomeStruct {
        uint8_t first;
        uint8_t second;
        uint8_t third;
    };
    

    那么它可能是一个选项。

    【讨论】:

    • 我们需要初始化一些位域,而不是无符号字符
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多