如何从C中的整数值获取逐位数据?

Bad*_*adr 95 c bit-manipulation

我想提取十进制数的位.

例如,7是二进制0111,我想得到0 1 1 1存储在bool中的所有位.我怎么能这样做?

好的,循环不是一个好选择,我可以为此做点什么吗?

for*_*ger 144

如果你想要n的第k位,那么就做

(n & ( 1 << k )) >> k
Run Code Online (Sandbox Code Playgroud)

在这里,我们创建一个蒙版,将蒙版应用于n,然后右移蒙版值以获得我们想要的位.我们可以更全面地写出来:

    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关位屏蔽的更多信息.

这是一个程序:

#include <stdio.h>
#include <stdlib.h>

int *get_bits(int n, int bitswanted){
  int *bits = malloc(sizeof(int) * bitswanted);

  int k;
  for(k=0; k<bitswanted; k++){
    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;
    bits[k] = thebit;
  }

  return bits;
}

int main(){
  int n=7;

  int  bitswanted = 5;

  int *bits = get_bits(n, bitswanted);

  printf("%d = ", n);

  int i;
  for(i=bitswanted-1; i>=0;i--){
    printf("%d ", bits[i]);
  }

  printf("\n");
}
Run Code Online (Sandbox Code Playgroud)

  • `(n >> k)&1`同样有效,并且不需要计算掩码,因为掩码是不变的,因为在掩蔽之前移位而不是相反. (67认同)

Joe*_*Joe 72

根据要求,我决定将我对食指答案的评论延伸到一个完整的答案.虽然他的答案是正确的,但它是不必要的复杂.此外,所有当前答案都使用带符号的ints来表示值.这是危险的,因为负值的右移是实现定义的(即不可移植),左移可能导致不确定的行为(参见这个问题).

通过将所需位右移到最低有效位位置,可以完成屏蔽1.无需为每个位计算新的掩码值.

(n >> k) & 1
Run Code Online (Sandbox Code Playgroud)

作为一个完整的程序,计算(并随后打印)单个位值的数组:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    unsigned
        input = 0b0111u,
        n_bits = 4u,
        *bits = (unsigned*)malloc(sizeof(unsigned) * n_bits),
        bit = 0;

    for(bit = 0; bit < n_bits; ++bit)
        bits[bit] = (input >> bit) & 1;

    for(bit = n_bits; bit--;)
        printf("%u", bits[bit]);
    printf("\n");

    free(bits);
}
Run Code Online (Sandbox Code Playgroud)

假设您要在这种情况下计算所有位,而不是特定位,则可以进一步将循环更改为

for(bit = 0; bit < n_bits; ++bit, input >>= 1)
    bits[bit] = input & 1;
Run Code Online (Sandbox Code Playgroud)

input在适当的位置进行了修改,从而允许使用恒定宽度的单比特移位,这在某些架构上可能更有效.


wal*_*lyk 9

这是一种方法 - 还有许多其他方法:

bool b[4];
int v = 7;  // number to dissect

for (int j = 0;  j < 4;  ++j)
   b [j] =  0 != (v & (1 << j));
Run Code Online (Sandbox Code Playgroud)

很难理解为什么不希望使用循环,但展开循环很容易:

bool b[4];
int v = 7;  // number to dissect

b [0] =  0 != (v & (1 << 0));
b [1] =  0 != (v & (1 << 1));
b [2] =  0 != (v & (1 << 2));
b [3] =  0 != (v & (1 << 3));
Run Code Online (Sandbox Code Playgroud)

或者评估最后四个语句中的常量表达式:

b [0] =  0 != (v & 1);
b [1] =  0 != (v & 2);
b [2] =  0 != (v & 4);
b [3] =  0 != (v & 8);
Run Code Online (Sandbox Code Playgroud)