【问题标题】:Iterate through bits in C遍历 C 中的位
【发布时间】:2014-12-12 05:12:56
【问题描述】:

我有一个大字符 *str,其中前 8 个字符(如果我没记错的话等于 64 位)代表一个位图。有没有办法遍历这 8 个字符并查看哪些位是 0?我在理解位的概念时遇到了很多麻烦,因为您无法在代码中“看到”它们,所以我想不出任何方法来做到这一点。

【问题讨论】:

  • 建议显示示例“前 8 个字符”。 “前 8 个字符”然后是“这 4 个字符”是什么意思?
  • 4 只是一个错字。当我说前 8 个字符时,我的意思是 str[1,2,...,8]
  • 你的意思是 0...7 而不是 1...8 吗?因为 C 中的数组索引从 0 开始。

标签: c bit bitarray


【解决方案1】:

假设你只有一个字节,一个字符my_char。您可以使用按位运算符和位移来测试单个位。

unsigned char my_char = 0xAA;
int what_bit_i_am_testing = 0;

while (what_bit_i_am_testing < 8) {
  if (my_char & 0x01) {
     printf("bit %d is 1\n", what_bit_i_am_testing);
  }
  else {
     printf("bit %d is 0\n", what_bit_i_am_testing);
  }

  what_bit_i_am_testing++;
  my_char = my_char >> 1;
}

对您来说必须是新的部分是&gt;&gt; 运算符。该运算符将“在左侧插入一个零并将每一位推到右侧,最右边的将被丢弃”。

对于右位移 1,这不是一个非常技术性的描述。

【讨论】:

  • 最好强调 my_char 必须是 unsigned 才能使此代码对所有值都正确工作(并且对于某些值不会永远运行)。
  • 是的,你是对的。但由于他说他的上下文是位图图像,为了清晰简洁,我省略了所有这些考虑。太多的信息可能会让新手感到困惑。
  • 感谢您的回答。你为什么使用 my_char & 0x01?
  • 这是重要的部分,它是一个位掩码。阅读en.wikipedia.org/wiki/Mask_(computing)他们把它放在那里
  • @Jean-BaptisteYunès 为什么不合适? my_char 可以只是一个临时变量...my_char = my_bitmap[1234];
【解决方案2】:

这是一种迭代无符号整数的每个设置位的方法(使用无符号整数而不是有符号整数来定义明确的行为;任何宽度的无符号都应该没问题),一次一位。

定义以下宏:

#define LSBIT(X)                    ((X) & (-(X)))
#define CLEARLSBIT(X)               ((X) & ((X) - 1))

然后你可以使用下面的习语来迭代设置的位,LSbit first:

unsigned temp_bits;
unsigned one_bit;

temp_bits = some_value;
for ( ; temp_bits; temp_bits = CLEARLSBIT(temp_bits) ) {
    one_bit = LSBIT(temp_bits);
    /* Do something with one_bit */
}

我不确定这是否适合您的需求。你说你想检查0 位,而不是1 位——也许你可以按位反转初始值。同样对于多字节值,您可以将其放入另一个 for 循环中,一次处理一个字节/字。

【讨论】:

    【解决方案3】:

    little-endian 内存架构确实如此:

    const int cBitmapSize = 8;
    const int cBitsCount = cBitmapSize * 8;
    const unsigned char cBitmap[cBitmapSize] = /* some data */;
    
    for(int n = 0; n < cBitsCount; n++)
    {
      unsigned char Mask = 1 << (n % 8);
      if(cBitmap[n / 8] & Mask)
      {
        // if n'th bit is 1...
      }
    }
    

    【讨论】:

    • 还有大端的,为什么要提到呢?字节序仅与较大单元(短、整数和更大)内的字节顺序有关。幸运的是,大端、中端和小端系统的位顺序是相同的。
    【解决方案4】:

    在 C 语言中,字符是 8 位宽的字节,而在计算机科学中,通常以字节为基本单位来组织数据。

    在某些情况下,例如您的问题,数据作为布尔值存储在各个位中,因此我们需要一种方法来确定特定字节中的特定位是打开还是关闭。已经有一个解决方案可以解释how to do bit manipulations in C

    要检查位,通常的方法是将其与要检查的位相加:

    int isBitSet = bitmap & (1 << bit_position);
    

    如果在此操作后变量 isBitSet 为 0,则该位未设置。任何其他值都表示该位处于打开状态。

    【讨论】:

    • s/8-bit wide/at least 8-bit wide
    • 在 C 语言中,字符是 CHAR_BIT 宽字节。 CHAR_BIT至少 8。
    • @chux 唯一具有超八位字节的现代系统是高度专业化的嵌入式系统。没有现代超八位字节的通用计算架构,因此从实际角度来看,char 始终是 8 位。
    • @Tyler Durden 1 ) 这个question 深入探讨了关于罕见CHAR_BIT != 8 的当前情况。 2) 由于 C 不需要新系统使用CHAR_BIT == 8,未来系统可能使用超八位字节char
    • @Tyler Durden 3) 就像 2014 年的系统绝大多数使用 2 的补码来表示 int 一样,所以 int 溢出 应该 得到很好的定义。由于 C 规范将 int 溢出保留为未定义以适应那些旧的讨厌的过时符号大小、1 的补码、填充整数,因此更智能的编译器已经利用了这一点,并创建了打破依赖于明确定义的 2 的补码溢出的以前代码的代码.为什么程序员要依赖定义明确的 2 的补码溢出——因为“所有”现代系统都使用 2 的补码。
    【解决方案5】:

    对于一个字符b,您可以像这样简单地迭代:

    for (int i=0; i<8; i++) {
      printf("This is the %d-th bit : %d\n",i,(b>>i)&1);
    }
    

    然后您可以根据需要遍历字符。

    您应该了解的是,您不能直接操作位,您可以使用以 2 为底的数字的一些算术属性来计算以某种方式代表您想知道的某些位的数字。

    例如,它是如何工作的?在一个 char 中有 8 位。一个 char 可以看作是一个以 2 为基数的 8 位数字。如果 b 中的数字是 b7b6b5b4b3b2b1b0 (每个都是一个数字),那么 b>>i 是 b 向右移动 i 个位置(在左侧推入 0 )。所以,10110111 >> 2 就是 00101101,那么 &1 操作就隔离了最后一位(按位与运算符)。

    【讨论】:

    • 好的,既然你已经解决了,我建议包括&lt;limits.h&gt;并将8更改为CHAR_BIT
    • 顺便说一句,如果你有一些char b 等于10110111 的二进制值,你做b &gt;&gt; 2,你得到的是11101101,而不是00101101。这是因为char 默认为signed char,当对signed 变量执行右移时,符号位会向右移动。要使b &gt;&gt; 2 产生00101101,您必须声明unsigned char b
    • 我不想这么迂腐。他只需要关于位操作的基本建议。
    • 不要在这里学究气,特别是如果它只是几行信息。 OP(以及将来阅读此答案的其他用户)最终会遇到不同的问题。
    【解决方案6】:

    如果你想遍历所有字符。

    char *str = "MNO"; // M=01001101, N=01001110, O=01001111
    int bit = 0;
    
    for (int x = strlen(str)-1; x > -1; x--){ // Start from O, N, M
        
        printf("Char %c \n", str[x]);
     
        for(int y=0; y<8; y++){ // Iterate though every bit
        // Shift bit the the right with y step and mask last position
            if( str[x]>>y & 0b00000001 ){ 
                printf("bit %d = 1\n", bit);
            }else{
                printf("bit %d = 0\n", bit);
            }
            bit++;
        }
        
    }
    

    输出

    Char O
    bit 0 = 1
    bit 1 = 1
    bit 2 = 1
    bit 3 = 1
    bit 4 = 0
    bit 5 = 0
    bit 6 = 1
    bit 7 = 0
    Char N 
    bit 8 = 0
    bit 9 = 1
    bit 10 = 1
    ...
    

    【讨论】:

      猜你喜欢
      • 2020-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多