【问题标题】:Setting a bit field in C在 C 中设置位域
【发布时间】:2015-09-14 02:18:30
【问题描述】:

我正在尝试编写一个将位字段设置为某个值的函数。函数是int setField(int old, int hi, int lo, int new)。我需要它从旧值中获取位范围(lohi)并用新值替换它们。替换位范围后,函数必须返回新值(十进制)。

int setField (int oldValue, int hi, int lo, int newValue) 
{
    int old = (oldValue >> lo) & ( (1 << hi) - 1);

    int i;
    for(i = lo;i<=hi;i++)
    {
    int a = getBit(newValue,i);
    if(a == 1)
      setBit(newValue,i);
    if(a == 0)
      clearBit(newValue,i);
    }
    return newValue;
}

这里是clearbit和setbit的代码

int setBit (int value, int position)
{
     int a = (1<<position);

     return (value | a);
}

int clearBit (int value, int position)
{
    int a = (1 << position);

    return (value & (~(a)) );
}

我在返回新值时遇到问题(在位被修改后)任何帮助将不胜感激。

这里也是getBit的代码

int getBit (int value, int position)
{
    int a = (1<<position);
    if( (value & a) == 0)
      return 0;
    else if( (value & a) != 0)
      return 1;
}

【问题讨论】:

  • setBitclearBit 返回新值,但是当您调用它时,您并没有对结果做任何事情。
  • 你也从错误的论点中得到了旧的一点。
  • 您的“(十进制)”评论很奇怪——我认为您应该删除它。该值将是二进制的。
  • 您可以将getBit() 简化为:int getBit(int value, int position) { return (value &amp; (1 &lt;&lt; position)) != 0; }。或者您可以将a 保留为中间变量。

标签: c field bit bit-fields


【解决方案1】:

有一种无需循环的简单方法:

uint32_t setField(uint32_t old, int hi, int lo, uint32_t new)
{
    uint32_t mask = -(2 << hi) ^ -(1 << lo);
    return (old & ~mask) | (new & mask);
}

这里用于mask 的构造会生成一个掩码,例如0b000..00011111000 表示 hi=7,lo=4。

此处使用否定来创建掩码,因为对单个位集整数(如1 &lt;&lt; lo)求反会导致具有相同位集的值以及所有更高位。例如:

  1 << 4  =  16 = 0b000…0010000
-(1 << 4) = -16 = 0b111…1110000

对两个这样的掩码进行异或运算会产生一个值,其中设置了两个掩码不同的位范围。

请注意,这假设您想用new 中的相应范围替换位范围。如果您真的想从new 中的最低位开始,请将最后一行中的new 替换为(new &lt;&lt; lo)

【讨论】:

    【解决方案2】:

    您需要在返回之前捕获结果并使用它来分配变量:

    newValue = clearBit(newValue,i);
    

    【讨论】:

      【解决方案3】:

      您需要在对setBitclearBit 的调用中使用oldValue,并将结果分配回oldValue

      int setField (int oldValue, int hi, int lo, int newValue) 
      {
          int i;
          for(i = lo;i<=hi;i++)
          {
            int a = getBit(newValue,i);
            if(a == 1) {
              oldValue = setBit(oldValue,i);
            } else {
              oldValue = clearBit(oldValue,i);
            }
          }
          return oldValue;
      }
      

      也不需要显式测试a == 0,只需使用else 子句即可。

      【讨论】:

      • 你可能误解了我的意思,假设我给出了一个旧值 6 即 0000 0110 ,我将 hi 设置为 3(第 3 位)和 lo 设置为 0(第一位)所以现在范围是 0110 。现在我将 5 作为新值传递,即 0101 。该函数需要做的是将 0110 更改为 0101,然后以十进制返回 0000 0101 的值(在本例中为 5)。
      • 好吧,我好像只是把新旧颠倒了。您对代码中的所有内容都使用了newValue
      • 我试过你写的东西,我只是得到旧值没有改变。
      • 我忘了修正return 声明
      • 顺便说一句,数字不是十进制或二进制,它们只是数字。除非您以特定的基数打印它们,否则它们不会变成十进制或二进制。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多