在未签名的int中手动更改一组字节

Manually changing a group of bytes in an unsigned int

本文关键字:字节 一组 int      更新时间:2023-10-16

我正在与C一起工作,我正在尝试弄清楚如何在32位未签名的整数中更改一组位。

例如,如果我有

int a = 17212403u;

在二进制中,它变为 1000001101010001111110011。现在,假设我将这些位标记为这些位,它们以小末端格式排列,使得最大的权利代表这些位,第二个是右边的,那么二是两者,依此类推,依此类推,我该如何手动更改一组位?

例如,假设我想更改位,以使第11位到15位的小数为17。如何可能?

我正在考虑这样做:

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

,但我不确定从现在开始去哪里。

您(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)

第11至15位是5位,假设您是包括15位。5位是十六进制值:0x1f

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

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

接下来是将值17移至11位:17 << 11

然后,我们刻有或进入我们清除的5位:

unsigned int b = (a & ~(0x1f << 11)) | (17 << 11)

考虑使用位字段。这使您可以命名和访问整数的子段,就好像它们是结构的整数成员。

有关C Bitfields的信息,请参见:https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm

以下是使用Bitfields来完成您想要的代码。结构的" Midder5"成员保持位11-15。" Lower11"成员是低11位的填充物,因此" Midder5"成员将在正确的位置。

#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

当然,您需要在各个领域使用更有意义的命名。

请小心,Bitfields在不同的平台上可能会有所不同 - 因此它可能无法完全便携。