【问题标题】:How to clear bits of unsigned char array in C?如何清除 C 中无符号字符数组的位?
【发布时间】:2017-07-31 13:13:00
【问题描述】:

假设我有一个名为 backup 的 unsigned char 数组,我想在其中复制一些字节。但我想要做的是清除大部分位(从右到左 18 位)。我需要留下的是左边的两个位。这是我的尝试:

memcpy (buf, " AA", 3);
unsigned char backup[3];
memcpy( backup, buf, 3 ); // backup
int two_bits_backup;
two_bits_backup = (int) backup &= ~0b001111111111111111111111;

但它会产生错误: 左值需要作为赋值的左操作数

如何成功清除这两个位?

我要做的是清除这些位(粗体)

如果 two_bits_backup = 0b111111111111111111111111;

case two_bits_backup ==   0b110000000000000000000000;

我想将 unsigned char 数组转换为 int 然后清除它。

我在 C 和 32 位平台上使用它,其中 int 有 4 个字节。

【问题讨论】:

  • 如果backup 是一个无符号字符数组,则不能将其视为int。 (换句话说,(int)backup 是非常错误的,它没有做任何你想要的事情。)
  • 你知道吗,a&=b 是 a = a & b 的简写形式?结果你不能modily(int)备份,因为它是r-value
  • 代码中的backup 不是unsigned char *
  • 我不明白你在问什么。您能否提供示例输入/输出来演示您想要什么?
  • 我想将无符号字符串数组转换为整数,然后清除22位

标签: c bit-manipulation


【解决方案1】:

您收到的错误消息是因为您试图为数组赋值。即使您尝试强制转换,也无法将数组作为一个整体分配。

您需要单独对每个字节执行位清除,然后使用位移将各个位放入two_bits_backup

backup[0] &= ~0x3f;
backup[1] &= ~0xff;
backup[2] &= ~0xff;

two_bits_backup = backup[0] << 16;
two_bits_backup |= backup[1] << 8;
two_bits_backup |= backup[2];

请注意,这假定backup 中的字节是最高有效字节在前,最高有效位在前。

【讨论】:

  • 并且不要忘记将它们移到正确的位置以将它们存储到整数中。
  • @AndreKampling 完成
  • 无用/可能有害的演员表。
  • @AnttiHaapala 你是对的,隐式转换应该解决这个问题。移除了演员表。
  • @dbush 除非变量不是易失性的,如果是,则分配零,需要 3 次操作(ARM gcc 6.3)。
【解决方案2】:

另一种方法是使用备份一个指向 int 的指针:

two_bits_backup = *(int*)backup &= ~0b001111111111111111111111;

基于下面的 cmets,我要添加此注释:备份的大小必须为 [4](或更大)才能在大多数系统上正常工作而不会违反别名规则。

char backup[4];
or 
char *backup = malloc(4);

memcpy 仍然可以工作,就像以前 n= 3 一样。'&' 操作将处理高字节中可能存在的垃圾。

【讨论】:

  • 不好。 backup 只有 3 个字节,int 在 OP 的平台上是 4 个字节。这将写入数组的末尾,导致undefined behavior
  • 没有。这违反了严格的别名,并且是在具有比 x86 更严格的对齐限制的系统上获得SIGBUS 或其他故障的好方法。仅仅因为它在 x86 平台上“工作”并不意味着它不是无效的 C 代码。
  • 你说得对。不过,在大多数系统上都需要大小为“4”的备份才能正常工作。
【解决方案3】:

我不明白你到底想做什么。无符号字符是 1 个字节。所以如果你想提取前 2 位,你应该用 1100 0000 进行逻辑与并右移 6 位。

(backup[0] &= C0)>>6

对数组中的所有元素都采用相同的方式。

【讨论】:

    【解决方案4】:

    如果你想用一个char数组来管理一个24位整数,你可以这样操作(对于小端机器)。但是,恕我直言,这不是一种干净的方式。

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        unsigned char buf[3];
    
        // Backup should be sizeof(unsigned int) bytes because an int of 3 bytes doesn't exist!
        unsigned char backup[sizeof(unsigned int)];
        unsigned int two_bits_backup;
    
        memcpy (buf, " AA", sizeof(buf));
        // memset (buf, 0xD5, sizeof(buf));
    
        memset( backup, 0, sizeof(unsigned int));
        memcpy( backup, buf, sizeof(buf) ); // backup
    
        printf("%08X\n",*(unsigned int *)(backup));
    
        two_bits_backup = *(unsigned int *)(backup) &= ~0b001111111111111111111111;
    
        printf("%08X\n",two_bits_backup);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多