如何读/写在C / C任意位++ [英] How to read/write arbitrary bits in C/C++

查看:148
本文介绍了如何读/写在C / C任意位++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个字节B配11111111二进制值

Assuming I have a byte b with the binary value of 11111111

例如如何做我读开始在第二位3位的整数值或写四个整数位值开始在第五位?

How do I for example read a 3 bit integer value starting at the second bit or write a four bit integer value starting at the fifth bit?

推荐答案

2+的一些年后,我问这个问题,我想解释一下我所希望的方式解释它回来时,我还是一个完整的福利局和将是谁想要了解这个过程的人最有利的。

Some 2+ years after I asked this question I'd like to explain it the way I'd want it explained back when I was still a complete newb and would be most beneficial to people who want to understand the process.

首先,忘记了11111111例如价值,这是不是真的那么适合该过程的可视化解释。因此,让我们的初始值是 10111011 (187十进制),这将是一个小更说明这个过程的。

First of all, forget the "11111111" example value, which is not really all that suited for the visual explanation of the process. So let the initial value be 10111011 (187 decimal) which will be a little more illustrative of the process.

1 - 如何读取从第二位开始一个3位值:

    ___  <- those 3 bits
10111011 

的值是101,或5十进制,有2个可能的途径获得:

The value is 101, or 5 in decimal, there are 2 possible ways to get it:


  • 面具和转移

在该方法中,所需要的比特首先用值掩蔽 00001110 (14进制数)之后将其在适当位置移位

In this approach, the needed bits are first masked with the value 00001110 (14 decimal) after which it is shifted in place:

    ___
10111011 AND
00001110 =
00001010 >> 1 =
     ___
00000101

此的前pression是:(值和14)&GT;&GT; 1


  • 移位和掩码

这方法是相似的,但操作的顺序是相反的,这意味着原来的值被移位,然后蒙面用 00000111 (7)只留下最后3位

This approach is similar, but the order of operations is reversed, meaning the original value is shifted and then masked with 00000111 (7) to only leave the last 3 bits:

    ___
10111011 >> 1
     ___
01011101 AND
00000111
00000101

此的前pression是:(价值&GT;&GT; 1)及7

这两种方法都涉及复杂的相同量,并且因此不会在性能不同。

Both approaches involve the same amount of complexity, and therefore will not differ in performance.

2 - 如何写从第二位开始一个3位值:

在此情况下,初始值是已知的,而当这是在code的情况下,你也许可以想出一个方法来设置已知值到使用较少的运算另一个已知值,但在现实中,这是很少的情况下,大部分的时候code将既不知道的初始值,也不是其中一个是要被写入

In this case, the initial value is known, and when this is the case in code, you may be able to come up with a way to set the known value to another known value which uses less operations, but in reality this is rarely the case, most of the time the code will know neither the initial value, nor the one which is to be written.

这意味着,为了对要成功拼接到字节的新值,则目标位必须设定为零,在此之后,移位值代替,这是第一个步骤拼接:

This means that in order for the new value to be successfully "spliced" into byte, the target bits must be set to zero, after which the shifted value is "spliced" in place, which is the first step:

    ___ 
10111011 AND
11110001 (241) =
10110001 (masked original value)

第二步是转移的价值,我们希望在3位的写,说,我们要改变这种状况,从101(5)到110(6)

The second step is to shift the value we want to write in the 3 bits, say we want to change that from 101 (5) to 110 (6)

     ___
00000110 << 1 =
    ___
00001100 (shifted "splice" value)

第三步也是最后一步是移位拼接的价值拼接蒙面原始值:

The third and final step is to splice the masked original value with the shifted "splice" value:

10110001 OR
00001100 =
    ___
10111101

整个过程中的前pression是:(价值&安培; 241)| (6 LT;&LT; 1)

奖金 - 如何产生读写口罩:

当然,使用二进制到十进制转换器是远离优雅,尤其是在32位和64位的容器的情况下 - 十进制值变得疯狂大。它可以容易地生成与前pressions掩模,其中所述编译器可以在编译期间有效地解决:

Naturally, using a binary to decimal converter is far from elegant, especially in the case of 32 and 64 bit containers - decimal values get crazy big. It is possible to easily generate the masks with expressions, which the compiler can efficiently resolve during compilation:


  • 阅读面具面具和转变:((1 <<;&LT; FieldLength参数) - 1) - ;&LT; (字段索引 - 1),假定在第一比特的索引为1(不为零)

  • 阅读面膜移和面具:(1 LT;&LT; FieldLength参数) - 1 (索引不会在这方面发挥作用,因为它总是转移到第一位

  • 写屏蔽:刚刚反转面具倒腾面具前pression与运营商

  • read mask for "mask and shift": ((1 << fieldLength) - 1) << (fieldIndex - 1), assuming that the index at the first bit is 1 (not zero)
  • read mask for "shift and mask": (1 << fieldLength) - 1 (index does not play a role here since it is always shifted to the first bit
  • write mask : just invert the "mask and shift" mask expression with the ~ operator

它是如何工作(与3位场开始从上面的例子中,第二位)?

How does it work (with the 3bit field beginning at the second bit from the examples above)?

00000001 << 3
00001000  - 1
00000111 << 1
00001110  ~ (read mask)
11110001    (write mask)

同样的例子适用于更广泛的整数和任意位宽和领域的地位,对于移位和屏蔽相应的变化。

The same examples apply to wider integers and arbitrary bit width and position of the fields, with the shift and mask values varying accordingly.

另外请注意,范例中假设的无符号整数,这是你想要以使用整数作为便携式位字段替代使用(普通位字段是没有办法的标准保证可移植)是什么,都留和右移位插入一个填充0,这是不符合右移一个符号的整数的情况。

Also note that the examples assume unsigned integer, which is what you want to use in order to use integers as portable bit-field alternative (regular bit-fields are in no way guaranteed by the standard to be portable), both left and right shift insert a padding 0, which is not the case with right shifting a signed integer.

均匀简单:

使用这套宏(但只能在C ++中,因为它依赖于成员函数代​​):

Using this set of macros (but only in C++ since it relies on the generation of member functions):

#define GETMASK(index, size) (((1 << (size)) - 1) << (index))
#define READFROM(data, index, size) (((data) & GETMASK((index), (size))) >> (index))
#define WRITETO(data, index, size, value) ((data) = ((data) & (~GETMASK((index), (size)))) | ((value) << (index)))
#define FIELD(data, name, index, size) \
  inline decltype(data) name() { return READFROM(data, index, size); } \
  inline void set_##name(decltype(data) value) { WRITETO(data, index, size, value); }

您可以去简单的东西是:

You could go for something as simple as:

struct A {
  uint bitData;
  FIELD(bitData, one, 0, 1)
  FIELD(bitData, two, 1, 2)
};

和已实施作为属性位字段,你可以轻松地访问:

And have the bit fields implemented as properties you can easily access:

A a;
a.set_two(3);
cout << a.two();

替换 decltype 用gcc的的typeof pre-C ++ 11。

Replace decltype with gcc's typeof pre-C++11.

这篇关于如何读/写在C / C任意位++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆