Assuming I have a byte b with the binary value of 11111111
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?
Assuming I have a byte b with the binary value of 11111111
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?
You need to shift and mask the value, so for example...
If you want to read the first two bits, you just need to mask them off like so:
If you want to offset it you need to shift right N bits and then mask off the bits you want:
To read three bits like you asked in your question.
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.
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 - how to read a 3 bit value starting from the second bit:
The value is 101, or 5 in decimal, there are 2 possible ways to get it:
In this approach, the needed bits are first masked with the value
00001110
(14 decimal) after which it is shifted in place:The expression for this would be:
(value & 14) >> 1
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:The expression for this would be:
(value >> 1) & 7
Both approaches involve the same amount of complexity, and therefore will not differ in performance.
2 - how to write a 3 bit value starting from the second bit:
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:
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)
The third and final step is to splice the masked original value with the shifted "splice" value:
The expression for the whole process would be:
(value & 241) | (6 << 1)
Bonus - how to generate the read and write masks:
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 << fieldLength) - 1) << (fieldIndex - 1)
, assuming that the index at the first bit is 1 (not zero)(1 << fieldLength) - 1
(index does not play a role here since it is always shifted to the first bit~
operatorHow does it work (with the 3bit field beginning at the second bit from the examples above)?
The same examples apply to wider integers and arbitrary bit width and position of the fields, with the shift and mask values varying accordingly.
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.
Even easier:
Using this set of macros (but only in C++ since it relies on the generation of member functions):
You could go for something as simple as:
And have the bit fields implemented as properties you can easily access:
Replace
decltype
with gcc'stypeof
pre-C++11.