C中的getField方法

时间:2014-09-13 23:38:58

标签: c bit

我正在研究一种方法,该方法假设返回字段的值。完整性检查示例:如果字段是三位宽且无符号,则结果将是介于0和7之间的值,而不管位中值的实际位置如何。如果值已签名,则结果将介于-4和3之间。此外,如果值已签名,则仅当字段的最左位为1时才为负。在这种情况下,字段必须为符号扩展(即使所有位都在左边1)。我逻辑上看起来对我来说似乎是正确的,但似乎是关闭的。

在我的测试中,当它为0时,我得到了正确的结果;当它有点时,我会失败:某点

int getField (int value, int hi, int lo, int isSigned) {  
    int x = 0;
    //int result = 0;
    for(int i =lo; i < hi; i++){
        x |= (1 << i);
    }
    if(isSigned == 1){
        value |= ~x;
    }
    else{
        value &= x;
    }
    int finalresult = value >> lo;
    return finalresult;
}

1 个答案:

答案 0 :(得分:2)

而不是

int x = 0;
for(int i =lo; i < hi; i++){
    x |= (1 << i);
}

你可以这样做

int x = ((1 << (hi-lo)) - 1) - ((1 << lo) -1);

或从(hi-lo)中加/减1 - 这取决于 hi 位是否为“in”。

为什么?

 1            => 0000 0001
 1 << 5       => 0010 0000
(1 << 5) - 1  => 0001 1111

此外,负数采用U2表示法,因此如果您想要否定数字,则需要执行两个步骤:

  1. 反转所有位
  2. 添加1
  3. 因此value |= ~x是不够的(你将反转零,但不是其余部分,你仍然需要添加1)。您可以使用value ^= (-1)进行反转。这就是为什么案例 somepoint:somepoint 无效。

    我写过类似的东西:

    #include <cassert>
    
    int getField(int value, int hi, int lo, int isSigned) {
      int result = 0;
    
      assert(hi >= lo);
                                                // let say we are interested in folowing bits: 
                                                // (marked as 1)
                                                // value := 0001 1100
                                                // so:
                                                // hi := 5
                                                // lo := 2
                                                // and e.g.:
                                                // isSigned := 1
    
      isSigned = (value >> (hi-1)) & isSigned;  // isSigned will be 1 if (it was 
                                                // 1 and proper bit is set to 1)
                                                // ((0001 1100) >> 4) & 1
                                                //   0000 0001        & 1
                                                //   0000 0001
                                                // isSigned := 1
    
      value >>= lo;                             // move interested bits that they start at 0
                                                // ((0001 1100) >> 2
                                                //   0000 0111
                                                // value := 0000 0111
    
      hi -= lo;                                 // how many bits we want?
                                                // hi := 3
    
      isSigned &= (hi != 0);                    // hi == 0 <=> hi == lo 
                                                // => sign will be always 0 
                                                // 1 &= (3 != 0)
                                                // 1
                                                // isSigned := 1
    
      hi -= isSigned;                           // if the last bit should be sign-bit
                                                // don't evaluate it as value
                                                // hi := 2
    
      result = value & ((1 << hi) - 1);         // (1<<hi)-1 creates bit mask 
                                                // 0000 0111 & ((1 << 2) - 1)
                                                // 0000 0111 &      (100 - 1)
                                                // 0000 0111 &       011
                                                // 0000 0011
                                                // result := 3
    
      if (isSigned)                             // true
        return -result;                         // return inverted result
                                                // -3
      return result;                            // if false return result
    }
    
    int main()
    {
      assert(0 == getField(0, 0, 0, 0));
      assert(0 == getField(0, 0, 0, 1));
      assert(0 == getField(15, 0, 0, 0));
      assert(0 == getField(15, 0, 0, 1));
      assert(0 == getField(15, 1, 1, 0));
      assert(0 == getField(15, 3, 3, 1));
      assert(0 == getField(0, 3, 0, 0));
      assert(0 == getField(0, 4, 0, 1));
                                            // (sign bit)[value bits]
      assert(1 == getField(1, 1, 0, 0));    // 000[1]
      assert(0 == getField(1, 1, 0, 1));    // 000(1)
    
      assert(3 == getField(15, 2, 0, 0));   // 11[11]
      assert(1 == getField(15, 2, 1, 0));   // 11[1]1
      assert(7 == getField(15, 4, 1, 0));   // [111]1
    
      assert(2 == getField(5, 4, 1, 0));    // [010]1
      assert(2 == getField(5, 3, 1, 0));    // 0[10]1
      assert(5 == getField(10, 4, 1, 0));   // [101]0
      assert(1 == getField(10, 3, 1, 0));   // 1[01]0
    
      assert(-1 == getField(15, 2, 0, 1));   // 11(1)[1]
      assert(0 == getField(15, 2, 1, 1));    // 11(1)1
      assert(-3 == getField(15, 4, 1, 1));   // (1)[11]1
    
      assert(2 == getField(5, 4, 1, 1));     // (0)[10]1
      assert(0 == getField(5, 3, 1, 1));     // 0(1)[0]1
      assert(-1 == getField(10, 4, 1, 1));   // (1)[01]0
      assert(1 == getField(10, 3, 1, 1));    // 1(0)[1]0
      assert(-2 == getField(12, 4, 1, 1));   // (1)[10]0
      assert(-2 == getField(10, 4, 0, 1));   // (1)[010]
    
      assert(-3 == getField(28, 5, 2, 1));    // 000(1) [11]00
    }
    

    没有循环。 2跳((hi != 0)if(isSigned))但对我来说VCv120在发布模式下以某种方式处理第一个,所以在代码中我只得到if()。我不知道如何摆脱它。

    也没有乘法(<< - 位移而不是乘法时间2),并且只有4次减法。不确定哪一个会更快......剩下的那个跳......

    再一次功能(这次没有评论)

    int getField(int value, int hi, int lo, int isSigned) {
      int result = 0;
      assert(hi >= lo);
      isSigned = (value >> (hi-1)) & isSigned;
      value >>= lo;
      hi -= lo;
      isSigned &= (hi != 0);
      hi -= isSigned;
      result = value & ((1 << hi) - 1);
      if (isSigned)
        return -result;
      return result;
    }
    

    修改

    我设法稍微清理代码:

    int getField(int value, int hi, int lo, int isSigned) {
      assert(hi >= lo);
    
      hi -= lo;
      value >>= lo;
      value &= ((1 << hi) - 1);
      isSigned <<= (hi - 1);
      isSigned &= value;
      if (isSigned && (hi != 0)) {
        value -= isSigned;
        value = ~value + 1;
      }
      return value;
    }
    

    但是生成的asm有2次跳转......

    1. if(isSigned
    2. &安培;&安培; (嗨!= 0))
    3. 编辑2

      在此版本中:

      int getField(int value, int hi, int lo, int isSigned) {
        assert(hi >= lo);
      
        hi -= lo;
        isSigned &= (hi != 0);
        value >>= lo;
        value &= ((1 << hi) - 1);
        isSigned <<= (hi - 1);
        isSigned &= value;
        if (isSigned) {
          value -= isSigned;
          value = ~value + 1;
        }
        return value;
      }
      

      只有一次跳跃。