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


99

我想提取十进制数的位。

例如,7是二进制0111,我想获取0 1 1 1存储在bool中的所有位。我该怎么办?

好的,循环不是一个好选择,我可以为此做点其他事情吗?

Answers:


154

如果您想要n的第k位,则执行

(n & ( 1 << k )) >> k

在这里,我们创建一个掩码,将掩码应用于n,然后右移掩码的值以获取所需的位。我们可以将其更完整地写为:

    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;

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

这是一个程序:

#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");
}

70
(n >> k) & 1是同等有效的,并且不需要计算掩码,因为掩码是恒定的,这是由于掩码之前发生了移位,而不是相反。

@Joe您可以解释一下吗?
Dan Rosenstark 2014年

1
@Yar扩展了我的评论,并按要求添加了新答案
Joe

当使用已知的位来获取信息时(即用于网络协议,例如Websockets),将数据强制转换为a struct也会很有用,因为您只需一次操作即可获得所有必需的数据。
Myst 2015年

@forefinger,能否请您发布代码示例输出。
Ashish Ahuja,

83

根据要求,我决定将对食指答案的评论扩展为完整的答案。尽管他的回答是正确的,但不必要的复杂。此外,所有当前答案均使用带符号ints表示值。这很危险,因为负值的右移是实现定义的(即不可移植的),而左移会导致不确定的行为(请参见此问题)。

通过将所需位右移到最低有效位位置,可以使用进行屏蔽1。无需为每个位计算新的掩码值。

(n >> k) & 1

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

#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);
}

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

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

这样就可以进行修改input,从而允许使用恒定宽度的单位位移,这在某些体系结构上可能更有效。


5

这是一种实现方法-还有很多其他方法:

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

for (int j = 0;  j < 4;  ++j)
   b [j] =  0 != (v & (1 << j));

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

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));

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

b [0] =  0 != (v & 1);
b [1] =  0 != (v & 2);
b [2] =  0 != (v & 4);
b [3] =  0 != (v & 8);

3

这是一种非常简单的方法。

int main()
{
    int s=7,l=1;
    vector <bool> v;
    v.clear();
    while (l <= 4)
    {
        v.push_back(s%2);
        s /= 2;
        l++;
    }
    for (l=(v.size()-1); l >= 0; l--)
    {
        cout<<v[l]<<" ";
    }
    return 0;
}

1

@prateek谢谢您的帮助。我用注释重写了该函数,以便在程序中使用。增加8以获取更多位(最多32个整数)。

std::vector <bool> bits_from_int (int integer)    // discern which bits of PLC codes are true
{
    std::vector <bool> bool_bits;

    // continously divide the integer by 2, if there is no remainder, the bit is 1, else it's 0
    for (int i = 0; i < 8; i++)
    {
        bool_bits.push_back (integer%2);    // remainder of dividing by 2
        integer /= 2;    // integer equals itself divided by 2
    }

    return bool_bits;
}

1

如果您不希望有任何循环,则必须将其写出:

#include <stdio.h>
#include <stdbool.h>

int main(void)
{
    int num = 7;

    #if 0
        bool arr[4] = { (num&1) ?true: false, (num&2) ?true: false, (num&4) ?true: false, (num&8) ?true: false };
    #else
        #define BTB(v,i) ((v) & (1u << (i))) ? true : false
        bool arr[4] = { BTB(num,0), BTB(num,1), BTB(num,2), BTB(num,3)};
        #undef BTB
    #endif

    printf("%d %d %d %d\n", arr[3], arr[2], arr[1], arr[0]);

    return 0;
}

如此处所示,这在初始化程序中也有效。


0
#include <stdio.h>

int main(void)
{
    int number = 7; /* signed */
    int vbool[8 * sizeof(int)];
    int i;
        for (i = 0; i < 8 * sizeof(int); i++)
        {
            vbool[i] = number<<i < 0;   
            printf("%d", vbool[i]);
        }
    return 0;
}

0

使用 std::bitset

int value = 123;
std::bitset<sizeof(int)> bits(value);
std::cout <<bits.to_string();

这是一种有用的方法,但是示例中存在错误。bitset <n>,n是位数,因此sizeof(int)的使用是错误的。
周杰伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.