【问题标题】:Looping through Bits C循环通过位 C
【发布时间】:2016-01-05 10:54:50
【问题描述】:

我正在尝试遍历 unsigned char 的位,但我不确定从哪里开始,最终,我将对位执行其他按位操作,例如 ~ 和 xor..等。

【问题讨论】:

  • 您是否考虑一次对所有这些进行操作?

标签: c bit-manipulation bit


【解决方案1】:

循环位可以通过多种方式完成:

  • 您可以在移动值时执行破坏性循环,并根据您希望枚举位的顺序测试初始位或最终位,或者
  • 您可以执行非破坏性循环,当您使用按位 AND 来测试具有单比特 掩码 的数字时,该数字由左移 1 产生。

这是第一种方法的示例:

unsigned int bits = ...;
while (bits) {
    if (bits & 1) {
        // Current bit is set to 1
    } else {
        // Current bit is set to 0
    }
    bits >>= 1;
}

如果您想在达到零后继续使用位,请制作一个单独的计数器。

这是第二种方法的示例:

unsigned int bits = ...;
for (int pos = 0 ; pos != 16 ; pos++) {
    if (bits & (1 << pos)) {
        // Current bit is set to 1
    } else {
        // Current bit is set to 0
    }
}

【讨论】:

  • 如果要对最后 1 位之后的 0 位采取操作,则您的第一个示例不好,因为它会在 bits 为 0 时停止。
  • @ShadowRanger 这是一个公平的观点 - 我向 OP 提到了它,谢谢!
【解决方案2】:

此函数将允许您遍历一个单词中的所有设置位:

inline size_t next_bit(uint64_t bf, size_t bit) {
    return ctz(bf & ~((1UL << bit) -1));
}

ctz 函数计算应由编译器作为内置函数提供的尾随零的数量。对于 gcc 和 llvm,您可以使用以下内容(请注意,对于 x86 上的 0ctz 未定义,因此需要修复):

inline size_t ctz(uint64_t x) { return x ? __builtin_ctzll(x) : 64; }

这是一个如何在 for 循环中使用它的示例:

for (size_t i = next_bit(bf, 0); i < 64; i = next_bit(bf, i + 1))
    // the i-th bit is set.

该函数通过清除ith 位之前的所有位并计算尾随零的数量来工作,这将为您提供ith 位之后的下一个设置位。清除这些位的方法是首先将一个位移到ith 位置,减去一个将所有位设置为低于ith 位的位。然后我们可以NOT 掩码来获取i 之后的所有位,以便AND 操作将删除i 之后的所有位。 ctz 完成剩下的工作。

对于 unsigned char 来说,这有点(双关语)矫枉过正,但我​​无法抗拒。老实说,对于 8 位字,您最好使用其他答案中建议的简单 while 循环。

【讨论】:

    【解决方案3】:

    嗯,从最低位到最高位,你可以这样循环:

    unsigned char somebyte = ...;
    for (int i = 0; i < 8; ++i, somebyte >>= 1) {
        if (somebyte & 0x1) {
            // Do stuff for 1 bit
        } else {
            // Do stuff for 0 bit
        }
    }
    

    不过,这是一个非常普遍的用例;通常,您希望并行化您的工作(一次对整个字节进行操作),或仅对 1 位进行操作(并在用完时停止而不是完成所有八个循环)等。需要更多上下文来解决特定问题问题而不是一般的循环。 Many specific problems are most efficiently solved with clever bit twiddling hacks.

    【讨论】:

      【解决方案4】:
      #define BIT(a,b)    (a & (1<<b))
      
      void printBits(unsigned char c){
          int i;
      
          char bits[9];
          for( i=0;i<8;i++){
              bits[i]=BIT(c,i)?'1':'0';
      
          }
          bits[8]=0;
          char *fmt=isalpha(c)
                  ?"'%c'\t= '%s'\n"
                  :" %d\t= '%s'\n";
          printf(fmt,c,bits);
      }
      
      
      int main(){
      
      
          printBits('A');
          printBits('B');
          printBits(1);
          printBits(2);
          printBits(3);
          return 0;
      }
      

      【讨论】:

      • 要访问单个位,请使用宏 BIT(char,BitPos) ,其中对于 char (BYTE),BitPos 在 [0-7] 的范围内。
      【解决方案5】:

      此方法允许将数组的索引与枚举器中的值进行映射,而不管元素的顺序或数组中存储了多少元素:

      typedef NS_OPTIONS(uint8_t, CaptureDeviceConfigurationControlPropertyBit) {
          CaptureDeviceConfigurationControlPropertyBitTorchLevel       = 1<< 0,
          CaptureDeviceConfigurationControlPropertyBitLensPosition     = 1<< 1,
          CaptureDeviceConfigurationControlPropertyBitExposureDuration = 1<< 2,
          CaptureDeviceConfigurationControlPropertyBitISO              = 1<< 3,
          CaptureDeviceConfigurationControlPropertyBitZoomFactor       = 1<< 4,
      };
      
      typedef CaptureDeviceConfigurationControlPropertyBit CaptureDeviceConfigurationControlPropertyBitMask;
      CaptureDeviceConfigurationControlPropertyBitMask mask = (CaptureDeviceConfigurationControlPropertyBitTorchLevel |
                                                               CaptureDeviceConfigurationControlPropertyBitLensPosition|
                                                               CaptureDeviceConfigurationControlPropertyBitExposureDuration|
                                                               CaptureDeviceConfigurationControlPropertyBitISO|
                                                               CaptureDeviceConfigurationControlPropertyBitZoomFactor);
                                                                   
      do{
          printf("mask\t==\t%d\n", (CaptureDeviceConfigurationControlPropertyBitMask)mask);
      } while((mask ^= mask & (0- mask)) != 0.0);
      

      【讨论】:

        【解决方案6】:
        Void PrintBits(unsigned int no)
        {
        Unsigned int mask = 0x8000;//=1000 0000 0000 0000 for 16 bit integers
        For(I=0;I<16;I++){
            If((i&mask)!=0)printf("1");
            Else printf ("0");
            Mask>>=1;
            If(i%4==0)printf (" ");
        }
        
        }
        

        如果您不理解此代码,请发表评论,我 24x7 全天候在线为您服务。

        【讨论】:

        • 如果你可以打印 int 你可以打印任何东西。对于 char 使用掩码 0x80,对于循环也限制为 8 次迭代。
        • 使用这个链接link, link, link
        猜你喜欢
        • 2012-01-02
        • 1970-01-01
        • 2017-04-27
        • 1970-01-01
        • 1970-01-01
        • 2014-04-27
        • 1970-01-01
        • 2013-03-13
        • 1970-01-01
        相关资源
        最近更新 更多