Dividing a bit string into three parts in C - c

I currently have a integer value that was read from an input file as a hexadecimal. I need to divide the 32 bit bitstream into three separate parts in order to manipulate it. The desired output is below:
desired output:
In this, V is my input value, left is the first X1 digits, next is the digits between X1 and X2, and last is the digits from X2 to the end. There is a constraint that each subsection must be greater than 0 in length.
What makes this difficult is that the location where I am splitting x varies (X1 and X2 can change)
Is there a good way to split these up?

The splitter() function here does the job you ask for. It takes quite a lot of arguments, unfortunately. There's the value to be split (value), the size of the chunk at the least significant end of the value (p1), the size of the middle chunk (p2), and then pointers to the high, medium and low values (hi_val, md_val, lo_val).
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
static void splitter(uint32_t value, unsigned p1, unsigned p2, uint32_t *hi_val, uint32_t *md_val, uint32_t *lo_val)
{
assert(p1 + p2 < 32);
*lo_val = value & ((1U << p1) - 1);
value >>= p1;
*md_val = value & ((1U << p2) - 1);
value >>= p2;
*hi_val = value;
}
static void test_splitter(uint32_t value, int p1, int p2)
{
uint32_t hi_val;
uint32_t md_val;
uint32_t lo_val;
splitter(value, p1, p2, &hi_val, &md_val, &lo_val);
printf("0x%.8" PRIX32 " (%2u,%2u,%2u) = 0x%.4" PRIX32 " : 0x%.4" PRIX32 " : 0x%.4" PRIX32 "\n",
value, (32 - p1 - p2), p2, p1, hi_val, md_val, lo_val);
}
int main(void)
{
uint32_t value;
value = 0xFFFFFFFF;
test_splitter(value, 9, 11);
value = 0xFFF001FF;
test_splitter(value, 9, 11);
value = 0x000FFE00;
test_splitter(value, 9, 11);
value = 0xABCDEF01;
test_splitter(value, 10, 6);
test_splitter(value, 8, 8);
test_splitter(value, 13, 9);
test_splitter(value, 10, 8);
return 0;
}
The test_splitter() function allows for simple testing of a single value plus the sections it is to be split in, and main() calls the test function a number of times.
The output is:
0xFFFFFFFF (12,11, 9) = 0x0FFF : 0x07FF : 0x01FF
0xFFF001FF (12,11, 9) = 0x0FFF : 0x0000 : 0x01FF
0x000FFE00 (12,11, 9) = 0x0000 : 0x07FF : 0x0000
0xABCDEF01 (16, 6,10) = 0xABCD : 0x003B : 0x0301
0xABCDEF01 (16, 8, 8) = 0xABCD : 0x00EF : 0x0001
0xABCDEF01 (10, 9,13) = 0x02AF : 0x006F : 0x0F01
0xABCDEF01 (14, 8,10) = 0x2AF3 : 0x007B : 0x0301
If any of the sections is larger than 16, the display gets spoiled — but the code still works.
In theory, the 1U values could be a 16-bit quantity, but I'm assuming that the CPU is working with 32-bit int. There are ways (UINT32_C(1)) to ensure that it is a 32-bit value, but that's probably OTT. The code explicitly forces 32-bit unsigned integer values, and prints them as such.

If i understand your question, you want to allocate data. Look alloca malloc fucntions.

Related

Convert signed int of variable bit size

I have a number of bits (the number of bits can change) in an unsigned int (uint32_t). For example (12 bits in the example):
uint32_t a = 0xF9C;
The bits represent a signed int of that length.
In this case the number in decimal should be -100.
I want to store the variable in a signed variable and gets is actual value.
If I just use:
int32_t b = (int32_t)a;
it will be just the value 3996, since it gets casted to (0x00000F9C) but it actually needs to be (0xFFFFFF9C)
I know one way to do it:
union test
{
signed temp :12;
};
union test x;
x.temp = a;
int32_t result = (int32_t) x.temp;
now i get the correct value -100
But is there a better way to do it?
My solution is not very flexbile, as I mentioned the number of bits can vary (anything between 1-64bits).
But is there a better way to do it?
Well, depends on what you mean by "better". The example below shows a more flexible way of doing it as the size of the bit field isn't fixed. If your use case requires different bit sizes, you could consider it a "better" way.
unsigned sign_extend(unsigned x, unsigned num_bits)
{
unsigned f = ~((1 << (num_bits-1)) - 1);
if (x & f) x = x | f;
return x;
}
int main(void)
{
int x = sign_extend(0xf9c, 12);
printf("%d\n", x);
int y = sign_extend(0x79c, 12);
printf("%d\n", y);
}
Output:
-100
1948
A branch free way to sign extend a bitfield (Henry S. Warren Jr., CACM v20 n6 June 1977) is this:
// value i of bit-length len is a bitfield to sign extend
// i is right aligned and zero-filled to the left
sext = 1 << (len - 1);
i = (i ^ sext) - sext;
UPDATE based on #Lundin's comment
Here's tested code (prints -100):
#include <stdio.h>
#include <stdint.h>
int32_t sign_extend (uint32_t x, int32_t len)
{
int32_t i = (x & ((1u << len) - 1)); // or just x if you know there are no extraneous bits
int32_t sext = 1 << (len - 1);
return (i ^ sext) - sext;
}
int main(void)
{
printf("%d\n", sign_extend(0xF9C, 12));
return 0;
}
This relies on the implementation defined behavior of sign extension when right-shifting signed negative integers. First you shift your unsigned integer all the way left until the sign bit is becoming MSB, then you cast it to signed integer and shift back:
#include <stdio.h>
#include <stdint.h>
#define NUMBER_OF_BITS 12
int main(void) {
uint32_t x = 0xF9C;
int32_t y = (int32_t)(x << (32-NUMBER_OF_BITS)) >> (32-NUMBER_OF_BITS);
printf("%d\n", y);
return 0;
}
This is a solution to your problem:
int32_t sign_extend(uint32_t x, uint32_t bit_size)
{
// The expression (0xffffffff << bit_size) will fill the upper bits to sign extend the number.
// The expression (-(x >> (bit_size-1))) is a mask that will zero the previous expression in case the number was positive (to avoid having an if statemet).
return (0xffffffff << bit_size) & (-(x >> (bit_size-1))) | x;
}
int main()
{
printf("%d\n", sign_extend(0xf9c, 12)); // -100
printf("%d\n", sign_extend(0x7ff, 12)); // 2047
return 0;
}
The sane, portable and effective way to do this is simply to mask out the data part, then fill up everything else with 0xFF... to get proper 2's complement representation. You need to know is how many bits that are the data part.
We can mask out the data with (1u << data_length) - 1.
In this case with data_length = 8, the data mask becomes 0xFF. Lets call this data_mask.
Thus the data part of the number is a & data_mask.
The rest of the number needs to be filled with zeroes. That is, everything not part of the data mask. Simply do ~data_mask to achieve that.
C code: a = (a & data_mask) | ~data_mask. Now a is proper 32 bit 2's complement.
Example:
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
const uint32_t data_length = 8;
const uint32_t data_mask = (1u << data_length) - 1;
uint32_t a = 0xF9C;
a = (a & data_mask) | ~data_mask;
printf("%"PRIX32 "\t%"PRIi32, a, (int32_t)a);
}
Output:
FFFFFF9C -100
This relies on int being 32 bits 2's complement but is otherwise fully portable.

evaluating segments of a byte in C

I am trying to do disassembly of Intel 8080 without using disassembly tables. I read in bytes of memory and split them into sections of bits: (7, 6), (5, 4, 3), (2, 1, 0). I want to know what are the numerical values of these sections, here is an example:
given this byte:
0b00110000
bits 7 and 6 evaluate to:
0b00 -> 0
bits 5 through 3:
0b110 -> 6
bits 2 through 0:
0b000 -> 0
Now, I am very inexperienced with C and I'm having a hard time coming up with an elegant and simple solution to this problem. So far my idea was the following:
Create 3 copies of the byte (1 per section)
Clear all bits apart from the ones I'm interested in (bitwise AND mask)
Shift the byte an appropriate number of bits
Read the value
would this do the job or is there a better way?
If you think about what needs to be done, you only need be concerned about unary >> shift operator and the & operator. It also helps to come up with a bit mask to isolate only those wanted bits out of whatever intermediate calculation as may be required. (a bit mask is simply a variable holding a number whose 1 bits and 0 bits can by used in a bitwise operation to give you your desired result).
Here, in all your separating of bits, you will only be concerned with the 2 or 3 lower bits after you shift to get your final result. In the case you are looking at (7,6), there are no further bits to mask leaving only the case where you are looking at the lower 3 bits that will require a mask.
From a bit-mask (or what's the magic number) standpoint, you want a mask that will preserve the last 3-bits and discard all remaining higher bits. So for an 8-bit value you want 00000111, or simply the number 7.
To begin, if you want to examine the highest 2 bits in an 8-bit number, then you simply need to shift your number by 6 to the right, e.g. given a byte b holding the total value 0x00110000 in your case, you need.
b >> 6;
There is no need to mask anything here since no higher bits remain.
For bits (5,4,3) in your example, you need to shift to the right by 3, then you will need to & the intermediate result with your mask (7 or b00000111) to get rid of the two bits that remain (6,7), e.g.
uint8_t mask = 7;
...
(b >> 3) & mask;
In the last part, your (2,1,0) bits, no shifting is required, you just need to wipe out all bits over bit 2, e.g. get rid of (7,6,5,4,3) using your mask,
b & mask
Putting that altogether, using exact width types, you can do something similar to the following. The program takes your byte value as its first argument (using 48, e.g. 0x0011000 by default if no argument is given) and outputs the results of the shifts and masks:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main (int argc, char *argv[]) {
uint64_t tmp = argc > 1 ? strtoul (argv[1], NULL, 0) : 48;
uint8_t b = 0,
mask = 7;
if (tmp > UINT8_MAX) {
fprintf (stderr, "input exceeds UINT8_MAX.\n");
return 1;
}
b = (uint8_t)tmp;
printf ("(7,6) 0x%02" PRIx8 "\n", b >> 6);
printf ("(5,4,3) 0x%02" PRIx8 "\n", (b >> 3) & mask);
printf ("(2,1,0) 0x%02" PRIx8 "\n", b & mask);
return 0;
}
Example Use/Output
$ /bin/bytes_233
(7,6) 0x00
(5,4,3) 0x06
(2,1,0) 0x00
Look things over and let me know if you have further questions.
To parse out specific bits of a binary value, we use bit shifts and bit masks. Any segment of bits can be obtained in this manner, using the concept of:
(data >> n) & mask
Where data is the raw data, n is the bit position where this data starts and mask is a bit mask of "all ones", corresponding to the length of the segment.
The mask of "all ones" can be obtained from knowing the segment size: (1u << size) - 1. If a segment's size is for example 3 bits, then 1<<3 gives 1000b. 1000b - 1 = 111b, which is a "all ones" mask of 3 bits.
So if we know the size in bits and the bit position (offset), we can get the data. Example:
#include <stdio.h>
#include <inttypes.h>
#define SEG1_BITS 2
#define SEG1_OFFSET 6
#define SEG2_BITS 3
#define SEG2_OFFSET 3
#define SEG3_BITS 2
#define SEG3_OFFSET 0
#define SEG1(d) ( ((uint32_t)d >> SEG1_OFFSET) & ((1u<<SEG1_BITS)-1) )
#define SEG2(d) ( ((uint32_t)d >> SEG2_OFFSET) & ((1u<<SEG2_BITS)-1) )
#define SEG3(d) ( ((uint32_t)d >> SEG3_OFFSET) & ((1u<<SEG3_BITS)-1) )
int main (void)
{
uint8_t data = 0x30;
printf("%"PRIu32"\n", SEG1(data));
printf("%"PRIu32"\n", SEG2(data));
printf("%"PRIu32"\n", SEG3(data));
return 0;
}
Advanced version with "X macro" to avoid code repetition:
#include <stdio.h>
#include <inttypes.h>
#define SEG_LIST \
/*bits, offset */ \
X(2, 6) \
X(3, 3) \
X(2, 0)
#define SEG(data, bits, n) ( ((uint32_t)data >> n) & ((1u<<bits)-1) )
int main (void)
{
uint8_t data = 0x30;
#define X(bits, n) printf("%"PRIu32"\n", SEG(data, bits, n));
SEG_LIST
#undef X
return 0;
}
Since the problem turned out to be of expansive nature, I had to generalise it and wrote this method:
uint8_t bitsAsValue(uint8_t* byte, int start, int end) {
uint8_t mask = 0b00000000;
uint8_t mask_setter = 0b00000001;
for (int i = start; i <= end; i++) {
mask |= (mask_setter << i);
}
uint8_t value = *byte & mask;
value = value >> start;
return value;
}
It will extract the value from a continuous segment of a byte.

Combining three bits to get a single integer value

So I have three variables each hold a 1 or a 0. These three form an address 0 - 7 when combined. for example
var1 = 1;
var2 = 0;
var3 = 1;
would be 5.
How would I go about combining these three variable to get an integer value? I have heard bit shifting operations would be the best way but I'm not sure how to do it. thanks.
Make sure the values are 0 or 1 for safety: AND with 1 do this
move these 0/1 values to proper positions: done with << operator
combine them: OR these values
if var1 = 1; var2 = 0; var3 = 0 should be 4, use this:
((var1 & 1) << 2) | ((var2 & 1) << 1) | (var3 & 1)
if var1 = 1; var2 = 0; var3 = 0 should be 1, use this:
((var3 & 1) << 2) | ((var2 & 1) << 1) | (var1 & 1)
var1 = 1, var2 = 0, var3 = 1, var4 = 1, var5 = 0, var6 = 0, var7 = 1, var8 = 0
byte = (var1<<7)+(var2<<6)+(var3<<5)+(var4<<4)+(var5<<3)+(var6<<2)+(var7<<1)+var8;
value of byte is 10110010
This works:
You shift the first bit 2 bits to the left with << 2, the second bit 1 bit to the left with << 1 and leave the last bit as it's in the last place.
That gives you 3 variables which are now 100, 000 and 001, You then or them together with | to get 101 i.e. 5.
I.e.
v1 is currently 001 in binary and you want it to be the 3rd bit, I.e. 100, so you need to shift it 2 to the left (v1 << 2)
Likewise, v2 is currently 000, and you want the 0 to be the 2nd bit, so you shift it 1 to the left (v2 << 1) to give 000 (trivial in this case but obviously different with a 1 here).
Finally, v3 is 001 and you want it to be the 3rd bit... It already is so we can leave it where it is.
Finally to combine them, we or the values together with |
100 |
000 |
001 =
101 = 5 in binary
#include <stdio.h>
#include <stdlib.h>
int main()
{
int v1=1, v2=0, v3=1;
int result;
result = (v1 << 2) | (v2 << 1) | v3;
printf("%d\n", result);
return 0;
}
In order to get a true answer you need to define what variable belongs to what bit position in the binary number you're trying to calculate and make sure you set the value of each variable to either zero or one or you'll be shifting the wrong bits around in the result.
In the code example below, the order of bits read from left to right is var3, var2, var1. var3 is known as the most significant bit, and var1 is known as the least significant bit.
If you want the value of 1, you set var1 to 1, then var2 and var3 to 0.
If you want the value of 4, you set var1 and var2 to 0 then set var3 to 1.
If you want the value of 5, you set var1 and var3 to 1 then set var2 to 0.
#include <stdio.h>
#include <stdlib.h>
int main(void){
int var1=1;
int var2=0;
int var3=1;
int res=(var3 << 2) + (var2 << 1) + var1;
printf("%d\n",res);
return 0;
}
If you want a somewhat easier-to-understand version, you can use this code:
#include <stdio.h>
#include <stdlib.h>
int main(void){
int LeastSignificantBit=1;
int MiddleBit=0;
int MostSignificantBit=1;
int Number=0;
Number=(MostSignificantBit << 2) + (MiddleBit << 1) + (LeastSignificantBit << 0);
printf("Number is %d\n",Number);
return 0;
}
I understand using << 0 is overkill, but I'm illustrating the fact that the least significant bit doesn't need to be shifted over.
When you bit shift some number you will just go from right to left on the memory. So, as we know, if we shift the number to the left it'll be multiplied by 2, since the base of the computer is binary. If we shift to the right, it'll be divided by 2.
like this:
decimal 5 --> binary 00101
decimal 10 --> binary 01010
Note that we've just shifted once to the left and we have the result of 5 multiplied by 2, therefore 10.
In your code I suggest you receive the variables by an scanf, the proceed to shift those and then sum them, like so:
#include <stdio.h>
int main(){
int var1, var2, var3;
scanf("%d %d %d", &var1, &var2, &var3);
printf("%d\n", (var1 << 2) + (var2 << 1) + var3);
return 0;
}
The code above we put the variable__<<__number_of_shifts. So in the first one we shift the var1 twice, the second one we shift once and at the last one we shift none. Then we sum all together and have your answer!
If the input variables are guaranteed to have value 1 or 0 then:
address = (var1 << 2) | (var2 << 1) | var3 ;
will do exactly what you want; however given that var1 etc. are integers an invalid and likely out-of-range address will be generated if the preconditions are not checked or limited.
A more flexible and maintainable implementation that allows simple address range extension would be to use an array rather than three separate variables. The fact that you numbered then in the first place rather suggests an array might be appropriate in any case):
#define ADDR_BITLEN 3
unsigned var[ADDR_BITLEN] ;
...
unsigned address = 0 ;
for( int bit = ADDR_BITLEN - 1; bit >= 0; bit++ )
{
address |= ((var[bit] == 0) ? 0 : 1) << bit ;
}
Now any number of bits up-to the bit length of an unsigned may be used for address simply by changing ADDR_BITLEN, further more the loop body ensures that an invalid address is not generated if address_bits[bit] is > 1 by selecting 0 or 1 explicitly, which would be somewhat cumbersome and hard to read and maintain if the array and loop were not used.

Strange result with bitshift operations

I am trying to understand bishift operations better so I wrote myself a little program.
unsigned char a = 240;
a= (a << 3) >> 7;
printf("a: %u\n",a);
Now I would imagine that the result would be something like :
11110000 // 240
10000000 // << 3
00000001 // >> 7
So 1, but I get 15. I am confused... Any help is appreciated!
Your problem is that this statement : (a << 3) converts the input to an int . So at this point you have 240 * 2 ^ 3 = 1920
00000000000000000000011110000000
Then you are dividing the previous result by 2 ^ 7 = 128 so you have : 15
00000000000000000000000000001111
Which is exactly what you are getting as a result.
If you wanted to truncate bits you could have used :
printf("a: %u\n",a & 1); //get only last bit so you would have 1 as a result!
printf("a: %u\n",a & 255); //get all 8 bits
Hope this helped!
The expressions are evaluated as (unsigned) ints. (default int promotion). Casting(truncation) to a narrower type only happens just prior to the final assignment.
When you shifted, it casted a into an integer type larger than 8 bits, so the top 4 bits were saved
#include <stdio.h>
int main() {
unsigned char a = 240;
a = (a << 3);
a = (a >> 7);
printf("a: %u\n",a);
return 0;
}
prints 1
While shifting the types are automatically promoted to int which is wider than char (most often). So, it can store all your bits.
To get what you expect you would have to do
a = a << 3;
a = a >> 7;
or
a = ((unsigned char)(a << 3)) >> 7;

How do I extract specific 'n' bits of a 32-bit unsigned integer in C?

Could anyone tell me as to how to extract 'n' specific bits from a 32-bit unsigned integer in C.
For example, say I want the first 17 bits of the 32-bit value; what is it that I should do?
I presume I am supposed to use the modulus operator and I tried it and was able to get the last 8 bits and last 16 bits as
unsigned last8bitsvalue=(32 bit integer) % 16
unsigned last16bitsvalue=(32 bit integer) % 32
Is this correct? Is there a better and more efficient way to do this?
Instead of thinking of it as 'extracting', I like to think of it as 'isolating'. Once the desired bits are isolated, you can do what you will with them.
To isolate any set of bits, apply an AND mask.
If you want the last X bits of a value, there is a simple trick that can be used.
unsigned mask;
mask = (1 << X) - 1;
lastXbits = value & mask;
If you want to isolate a run of X bits in the middle of 'value' starting at 'startBit' ...
unsigned mask;
mask = ((1 << X) - 1) << startBit;
isolatedXbits = value & mask;
Hope this helps.
If you want n bits specific then you could first create a bitmask and then AND it with your number to take the desired bits.
Simple function to create mask from bit a to bit b.
unsigned createMask(unsigned a, unsigned b)
{
unsigned r = 0;
for (unsigned i=a; i<=b; i++)
r |= 1 << i;
return r;
}
You should check that a<=b.
If you want bits 12 to 16 call the function and then simply & (logical AND) r with your number N
r = createMask(12,16);
unsigned result = r & N;
If you want you can shift the result. Hope this helps
Modulus works to get bottom bits (only), although I think value & 0x1ffff expresses "take the bottom 17 bits" more directly than value % 131072, and so is easier to understand as doing that.
The top 17 bits of a 32-bit unsigned value would be value & 0xffff8000 (if you want them still in their positions at the top), or value >> 15 if you want the top 17 bits of the value in the bottom 17 bits of the result.
There is a single BEXTR (Bit field extract (with register)) x86 instruction on Intel and AMD CPUs and UBFX on ARM. There are intrinsic functions such as _bextr_u32() (link requires sign-in) that allow to invoke this instruction explicitly.
They implement (source >> offset) & ((1 << n) - 1) C code: get n continuous bits from source starting at the offset bit. Here's a complete function definition that handles edge cases:
#include <limits.h>
unsigned getbits(unsigned value, unsigned offset, unsigned n)
{
const unsigned max_n = CHAR_BIT * sizeof(unsigned);
if (offset >= max_n)
return 0; /* value is padded with infinite zeros on the left */
value >>= offset; /* drop offset bits */
if (n >= max_n)
return value; /* all bits requested */
const unsigned mask = (1u << n) - 1; /* n '1's */
return value & mask;
}
For example, to get 3 bits from 2273 (0b100011100001) starting at 5-th bit, call getbits(2273, 5, 3)—it extracts 7 (0b111).
For example, say I want the first 17 bits of the 32-bit value; what is it that I should do?
unsigned first_bits = value & ((1u << 17) - 1); // & 0x1ffff
Assuming CHAR_BIT * sizeof(unsigned) is 32 on your system.
I presume I am supposed to use the modulus operator and I tried it and was able to get the last 8 bits and last 16 bits
unsigned last8bitsvalue = value & ((1u << 8) - 1); // & 0xff
unsigned last16bitsvalue = value & ((1u << 16) - 1); // & 0xffff
If the offset is always zero as in all your examples in the question then you don't need the more general getbits(). There is a special cpu instruction BLSMSK that helps to compute the mask ((1 << n) - 1).
If you need the X last bits of your integer, use a binary mask :
unsigned last8bitsvalue=(32 bit integer) & 0xFF
unsigned last16bitsvalue=(32 bit integer) & 0xFFFF
This is a briefer variation of the accepted answer: the function below extracts the bits from-to inclusive by creating a bitmask. After applying an AND logic over the original number the result is shifted so the function returns just the extracted bits.
Skipped index/integrity checks for clarity.
uint16_t extractInt(uint16_t orig16BitWord, unsigned from, unsigned to)
{
unsigned mask = ( (1<<(to-from+1))-1) << from;
return (orig16BitWord & mask) >> from;
}
Bitwise AND your integer with the mask having exactly those bits set that you want to extract. Then shift the result right to reposition the extracted bits if desired.
unsigned int lowest_17_bits = myuint32 & 0x1FFFF;
unsigned int highest_17_bits = (myuint32 & (0x1FFFF << (32 - 17))) >> (32 - 17);
Edit: The latter repositions the highest 17 bits as the lowest 17; this can be useful if you need to extract an integer from “within” a larger one. You can omit the right shift (>>) if this is not desired.
#define GENERAL__GET_BITS_FROM_U8(source,lsb,msb) \
((uint8_t)((source) & \
((uint8_t)(((uint8_t)(0xFF >> ((uint8_t)(7-((uint8_t)(msb) & 7))))) & \
((uint8_t)(0xFF << ((uint8_t)(lsb) & 7)))))))
#define GENERAL__GET_BITS_FROM_U16(source,lsb,msb) \
((uint16_t)((source) & \
((uint16_t)(((uint16_t)(0xFFFF >> ((uint8_t)(15-((uint8_t)(msb) & 15))))) & \
((uint16_t)(0xFFFF << ((uint8_t)(lsb) & 15)))))))
#define GENERAL__GET_BITS_FROM_U32(source,lsb,msb) \
((uint32_t)((source) & \
((uint32_t)(((uint32_t)(0xFFFFFFFF >> ((uint8_t)(31-((uint8_t)(msb) & 31))))) & \
((uint32_t)(0xFFFFFFFF << ((uint8_t)(lsb) & 31)))))))
int get_nbits(int num, int n)
{
return (((1<<n)-1) & num);
}
I have another method for accomplishing this. You can use a union of an integer type that has enough bits for your application and a bit field struct.
Example:
typedef thesebits
{
unsigned long first4 : 4;
unsigned long second4 : 4;
unsigned long third8 : 8;
unsigned long forth7 : 7;
unsigned long fifth3 : 3;
unsigned long sixth5 : 5;
unsigned long last1 : 1;
} thesebits;
you can set that struct up to whatever bit pattern you want. If you have multiple bit patterns, you can even use that in your union as well.
typedef thesebitstwo
{
unsigned long first8 : 8;
unsigned long second8 : 8;
unsigned long third8 : 8;
unsigned long last8 : 8;
} thesebitstwo;
Now you can set up your union:
typedef union myunion
{
unsigned long mynumber;
thesebits mybits;
thesebitstwo mybitstwo;
} myunion;
Then you can access the bits you want from any number you assign to the member mynumber:
myunion getmybits;
getmybits.mynumber = 1234567890;
If you want the last 8 bits:
last16bits = getmybits.mybitstwo.last8;
If you want the second 4 bits:
second4bits = getmybits.mybits.second4;
I gave two examples kind of randomly assigned different bits to show. You can set the struct bit-fields up for whatever bits you want to get. I made all of the variables type unsigned long but you can use any variable type as long as the number of bits doesn't exceed those that can be used in the type. So most of these could have been just unsigned int and some even could be unsigned short
The caveat here is this works if you always want the same set of bits over and over. If there's a reason you may need to vary which bits you're looking at to anything, you could use a struct with an array that keeps a copy of the bits like so:
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct bits32
{
bool b0 : 1;
bool b1 : 1;
bool b2 : 1;
bool b3 : 1;
bool b4 : 1;
bool b5 : 1;
bool b6 : 1;
bool b7 : 1;
bool b8 : 1;
bool b9 : 1;
bool b10 : 1;
bool b11 : 1;
bool b12 : 1;
bool b13 : 1;
bool b14 : 1;
bool b15 : 1;
bool b16 : 1;
bool b17 : 1;
bool b18 : 1;
bool b19 : 1;
bool b20 : 1;
bool b21 : 1;
bool b22 : 1;
bool b23 : 1;
bool b24 : 1;
bool b25 : 1;
bool b26 : 1;
bool b27 : 1;
bool b28 : 1;
bool b29 : 1;
bool b30 : 1;
bool b31 : 1;
} bits32;
typedef struct flags32 {
union
{
uint32_t number;
struct bits32 bits;
};
bool b[32];
} flags32;
struct flags32 assignarray ( unsigned long thisnumber )
{
struct flags32 f;
f.number = thisnumber;
f.b[0] = f.bits.b0;
f.b[1] = f.bits.b1;
f.b[2] = f.bits.b2;
f.b[3] = f.bits.b3;
f.b[4] = f.bits.b4;
f.b[5] = f.bits.b5;
f.b[6] = f.bits.b6;
f.b[7] = f.bits.b7;
f.b[8] = f.bits.b8;
f.b[9] = f.bits.b9;
f.b[10] = f.bits.b10;
f.b[11] = f.bits.b11;
f.b[12] = f.bits.b12;
f.b[13] = f.bits.b13;
f.b[14] = f.bits.b14;
f.b[15] = f.bits.b15;
f.b[16] = f.bits.b16;
f.b[17] = f.bits.b17;
f.b[18] = f.bits.b18;
f.b[19] = f.bits.b19;
f.b[20] = f.bits.b20;
f.b[21] = f.bits.b21;
f.b[22] = f.bits.b22;
f.b[23] = f.bits.b23;
f.b[24] = f.bits.b24;
f.b[25] = f.bits.b25;
f.b[26] = f.bits.b26;
f.b[27] = f.bits.b27;
f.b[28] = f.bits.b28;
f.b[29] = f.bits.b29;
f.b[30] = f.bits.b30;
f.b[31] = f.bits.b31;
return f;
}
int main ()
{
struct flags32 bitmaster;
bitmaster = assignarray(1234567890);
printf("%d\n", bitmaster.number);
printf("%d\n",bitmaster.bits.b9);
printf("%d\n",bitmaster.b[9]);
printf("%lu\n", sizeof(bitmaster));
printf("%lu\n", sizeof(bitmaster.number));
printf("%lu\n", sizeof(bitmaster.bits));
printf("%lu\n", sizeof(bitmaster.b));
}
The issue with this last example is that it's not compact. The union itself is only 4 bytes, but since you can't do pointers to bit-fields (without complicated and debatably "non-standard" code), then the array makes a copy of each boolean value and uses a full byte for each one, instead of just the bit, so it takes up 9x the total memory space (if you run the printf statement examples I gave, you'll see).
But now, you can address each bit one-by-one and use a variable to index each one, which is great if you're not short on memory.
By using the typedefs above and the assignarray function as a constructor for flags32, you can easily expand to multiple variables. If you're OK just addressing with .b# and not being able to use a variable, you can just define the union as flags32 and omit the rest of the struct. Then you also don't need the assignarray function, and you'll use much less memory.

Resources