代码之家  ›  专栏  ›  技术社区  ›  Veer Singh

手动更改无符号整数中的一组字节

  •  1
  • Veer Singh  · 技术社区  · 7 年前

    我正在使用C语言,我试图找出如何更改32位无符号整数中的一组位。

    例如,如果我有

    int a = 17212403u;
    

    在二进制中,它变成 1000001101010001111110011 . 现在,假设我标记了这些位,这些位以小端格式排列,使得最右边的位代表一个,右边的第二个是二个,以此类推,我如何手动更改一组位?

    例如,假设我想更改位,使第11位到第15位的十进制值为17。这怎么可能?

    我想通过这样做来达到这个范围:

    unsigned int range = (a << (sizeof(a) * 8) - 14) >> (28)
    

    3 回复  |  直到 7 年前
        1
  •  2
  •   Stephan Lechner    7 年前

    您将(1)首先必须清除位11。。15和(2)然后根据要设置的值设置位。为了实现(1),创建一个“掩码”,将所有位设置为 1 a & bitMask 将位设置为 0 . 然后,使用 | myValue <<

    int main(int argc, char** argv) {
    
        // Let's assume a range of 5 bits
        unsigned int bitRange = 0x1Fu;  // is ...00000000011111
    
        // Let's assume to position the range from bit 11 onwards (i.e. move 10 left):
        bitRange = bitRange << 10;             // something like 000000111110000000000
        unsigned int bitMask = ~bitRange;      // something like 111111000001111111111
        unsigned int valueToSet = (17u << 10); // corresponds to 000000101110000000000
    
        unsigned int a = (17212403u & bitMask) | valueToSet;
    
        return 0;
    }
    

    这是一个很长的版本来解释发生了什么。简而言之,你也可以写:

    unsigned int a = (17212403u & ~(0x1Fu << 10)) | (17u << 10)
    
        2
  •  2
  •   nos    7 年前

    0x1f

    然后将这5位11的位置向左移动: 0x1f << 11

    现在,我们有一个掩码,用于我们想在原始变量中清除的位11到15,我们通过反转掩码,逐位和带有反转掩码的变量来实现这一点: a & ~(0x1f << 11)

    17 << 11

    然后我们按位或将其转换为已清除的5位:

    unsigned int b = (a & ~(0x1f << 11)) | (17 << 11)
    
        3
  •  0
  •   Robert Blansett    7 年前

    考虑使用位字段。这允许您命名和访问整数的子部分,就像它们是结构的整数成员一样。

    有关C位字段的信息,请参阅: https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm

    #include <stdio.h>
    
    void showBits(unsigned int w)
    {
      unsigned int bit = 1<<31;
      while (bit > 0) 
      {
        printf("%d", ((bit & w) != 0)? 1 : 0);
        bit >>= 1;
      }
      printf("\n");
    }
    
    int main(int argc, char* argv[])
    {
      struct aBitfield {
          unsigned int lower11: 11;
          unsigned int middle5:  5;
          unsigned int upper16: 16;
      };
    
      union uintBits {
        unsigned int     whole;
        struct aBitfield parts;
      };
    
      union uintBits b;
    
      b.whole = 17212403u;
    
      printf("Before:\n");
      showBits(b.whole);
    
      b.parts.middle5 = 17;
    
      printf("After:\n"); 
      showBits(b.whole);    
    }
    

    程序输出:

    Before:
    00000001000001101010001111110011
    After:
    00000001000001101000101111110011
    

    但是要小心,位域在不同平台上的实现可能不同,因此它可能不完全可移植。