Best way to move 8 bits into 8 individual bytes [duplicate] - c

This question already has answers here:
How to create a byte out of 8 bool values (and vice versa)?
(8 answers)
Closed 3 years ago.
I have a status register with 8 bits. I would like to move each individual bit to a byte for further processing. Seems like it should be easy but every solution I come up with is convoluted. I was thinking about iterating through the bits with a for next loop and dumping them into an array but my solution way too messy.

Here's basically what you're trying to do. It uses bitwise operators and a uint8_t array to make each bit an individual byte:
void bits_to_bytes(uint8_t status, uint8_t bits[8])
{
int ctr;
for( ctr = 0; ctr < 8; ctr++ )
{
bits[ctr] = (status >> ctr) & 1;
}
}
OK, so a little more in-depth:
This code loops through the bits in a byte and then assigns bits[bit_number] to the bit_numberth bit of status.
If you want to reverse the order the bits are stored in, simply change bits[ctr] to bits[(8-1)-ctr].

For a start, you should be using uint8_t for eight-bit bit collections since char is fundamentally non-portable unless you add a lot of extra code for checking its size and signedness.
Something like this should suffice for your needs:
void BitsToBytes(uint8_t bits, uint8_t *bytes) {
for (int i = 0; i < 8; ++i) { // The type has exactly eight bits.
*bytes++ = (bits > 127); // 1 if high bit set, else 0.
bits = (bits & 0x7f) << 1; // Shift left to get next bit.
}
}
:
// Call with:
uint8_t inputBits = 0x42;
uint8_t outputBytes[8];
BitsToBytes(inputBits, outputBytes);
This takes a type with eight bits and a buffer of eight bytes, then places the individual bits into each byte of the array:
MSB LSB
+--------+
inputBits: |abcdefgh|
+--------+
+---+---+---+---+---+---+---+---+
outputBytes: | a | b | c | d | e | f | g | h |
+---+---+---+---+---+---+---+---+
If you want it to go the other way (where the LSB of the input is in element 0 of the array), you can simply change the body of the loop to:
*bytes++ = bits & 1; // 1 if low bit set, else 0.
bits = bits >> 1; // Shift right to get next bit.

You can use a double invocation of the ! operator to squash a zero/non-zero value to zero/one. Using this, the extracted value of bit n in status is !!(status & (1 << n)).
If you only have eight flags you might just create constants for the 8 values of 1 << n (0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80). This works particularly well if your flags all have individual names rather than numbers, so that you might have in a header file somewhere:
#define FLAG_FROB 0x01
#define FLAG_FOO 0x02
#define FLAG_BAR 0x04
#define FLAG_BAZ 0x08
#define FLAG_QUUX 0x10
Then in the code you'd just extract them as
flag_frob = !!(status & FLAG_FROB);
flag_foo = !!(status & FLAG_FOO);
flag_bar = !!(status & FLAG_BAR);
flag_baz = !!(status & FLAG_BAZ);
flag_quux = !!(status & FLAG_QUUX);

Related

Swapping bits in an integer in C, can you explain this function to me?

I want to write a function that receives an unsigned char and swaps between bit 2 and bit 4 and returns the new number.
I am not allowed to use if statement.
So I found this function, among other functions, but this was the most simple one to understand (or try to understand).
All other functions involve XOR which I don't really understand to be honest.
unsigned char SwapBits(unsigned char num)
{
unsigned char mask2 = ( num & 0x04 ) << 2;
unsigned char mask4 = ( num & 0x10 ) >> 2;
unsigned char mask = mask3 | mask5 ;
return ( num & 0xeb ) | mask;
}
Can someone explain me what happens here and most important, why?
Why AND is required here and why with hex address?
Why should I AND with 0xeb (255)? I know that's the range of char but why should I do that.
In short,
I know how to read codes. I understand this code, but I don't understand the purpose of each line.
Thanks.
First, the usual convention is that bits are numbered starting from 0 for the least significant bit and counting up. In this case, you have an 8-bit value, so the bits go from 0 on the right up to 7 on the left.
The function you posted still isn't quite right, but I think I see where you (it) was going with it. Here are the steps it's doing:
Pull out bit 2 (which is 3rd from the right) using a mask
Pull out bit 4 (which is 5th from the right) using a mask
Shift bit 2 left 2 positions so it's now in bit 4's original position
Shift bit 4 right 2 positions so it's now in bit 2's original position
Join these two bits together into one value that is now bits 2 and 4 swapped
Mask out (erase using &) only bits 2 and 4 from the original value
Join in (insert using |) the new swapped bits 2 and 4 to complete the transformation
I have rewritten the function to show each step one at a time to help make it clearer. In the original function or other examples you find, you'll see many of these steps all happen together in the same statement.
unsigned char SwapBits(unsigned char num)
{
// preserve only bit 2
unsigned char bit2 = num & 0x04;
// preserve only bit 4
unsigned char bit4 = num & 0x10;
// move bit 2 left to bit 4 position
unsigned char bit2_moved = bit2 << 2;
// move bit 4 right to bit 2 position
unsigned char bit4_moved = bit4 >> 2;
// put the two moved bits together into one swapped value
unsigned char swapped_bits = bit2_moved | bit4_moved;
// clear bits 2 and 4 from the original value
unsigned char num_with_swapped_bits_cleared = num & ~0x14;
// put swapped bits back into the original value to complete the swap
return num_with_swapped_bits_cleared | swapped_bits;
}
The second to last step num & ~0x14 probably needs some explanation. Since we want to save all the original bits except for bits 2 and 4, we mask out (erase) only the bits we're changing and leave all the others alone. The bits we want to erase are in positions 2 and 4, which are the 1s in the mask 0x14. So we do a complement (~) on 0x14 to turn it into all 1s everywhere except for 0s in bits 2 and 4. Then we AND this value with the original number, which has the effect of changing bits 2 and 4 to 0 while leaving all the others alone. This allows us to OR in the new swapped bits as the final step to complete the process.
You have to read about binary representation of number
unsigned char SwapBits(unsigned char num)
{
// let say that [num] = 46, it means that is is represented 0b00101110
unsigned char mask2 = ( num & 0x04 ) << 2;
// now, another byte named mask2 will be equal to:
// 0b00101110 num
// 0b00000100 0x04
// . .1. mask2 = 4. Here the & failed with . as BOTH ([and]) bits need to be set. Basically it keeps only numbers that have the 3rd bit set
unsigned char mask4 = ( num & 0x10 ) >> 2;
// 0b00101110 num
// 0b00010000 0x10 -> means 16 in decimal or 0b10000 in binary or 2^4 (the power is also the number of trailing 0 after the bit set)
// 0b00.....0 mask4 = 0, all bits failed to be both set
unsigned char mask = mask3 | mask5 ;
// mask will take bits at each position if either set by mask3 [or] mask5 so:
// 0b1001 mask3
// 0boo11 mask4
// 0b1011 mask
return ( num & 0xeb ) | mask; // you now know how it works ;) solve this one. PS: operation between Brackets have priority
}
If you are interested to learn the basics of bitwise operators you can take a look at this introduction.
After you build confidence you can try solving algorithms using only bitwise operators, where you will explore even deeper bitwise operations and see its impact on the runtime ;)
I also recommend reading Bit Twiddling Hacks, Oldies but Goodies!
b = ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; // reverse your byte!
Simple function to understand swap of bit 3 and 5:
if you want to swap bit index 3 and bit index 5, then you have to do the following:
int n = 0b100010
int mask = 0b100000 // keep bit index 5 (starting from index 0)
int mask2 = 0b1000 // keep bit index 3
n = (n & mask) >> 2 | (n & mask2) << 2 | (n & 0b010111);
// (n & mask) >> 2
// the mask index 5 is decrease by 2 position (>>2) and brings along with it the bit located at index 5 that it had captured in n thanks to the AND operand.
// | (n & mask2) << 2
// mask2 is increased by 2 index and set it to 0 since n didn't have a bit set at index 3 originally.
// | (n & 0b010111); // bits 0 1 2 and 4 are preserved
// since we assign the value to n all other bits would have been wiped out if we hadn't kept their original value thanks to the mask on which we do not perform any shift operations.

Bit operations for formatting and parsing custom protocol header in C [duplicate]

Say I have a byte like this 1010XXXX where the X values could be anything. I want to set the lower four bits to a specific pattern, say 1100, while leaving the upper four bits unaffected. How would I do this the fastest in C?
In general:
value = (value & ~mask) | (newvalue & mask);
mask is a value with all bits to be changed (and only them) set to 1 - it would be 0xf in your case. newvalue is a value that contains the new state of those bits - all other bits are essentially ignored.
This will work for all types for which bitwise operators are supported.
You can set all those bits to 0 by bitwise-anding with the 4 bits set to 0 and all other set to 1 (This is the complement of the 4 bits set to 1). You can then bitwise-or in the bits as you would normally.
ie
val &= ~0xf; // Clear lower 4 bits. Note: ~0xf == 0xfffffff0
val |= lower4Bits & 0xf; // Worth anding with the 4 bits set to 1 to make sure no
// other bits are set.
Use bitwise operator or | when you want to change the bit of a byte from 0 to 1.
Use bitwise operator and & when you want to change the bit of a byte from 1 to 0
Example
#include <stdio.h>
int byte;
int chb;
int main() {
// Change bit 2 of byte from 0 to 1
byte = 0b10101010;
chb = 0b00000100; //0 to 1 changer byte
printf("%d\n",byte); // display current status of byte
byte = byte | chb; // perform 0 to 1 single bit changing operation
printf("%d\n",byte);
// Change bit 2 of byte back from 1 to 0
chb = 0b11111011; //1 to 0 changer byte
byte = byte & chb; // perform 1 to 0 single bit changing operation
printf("%d\n",byte);
}
Maybe there are better ways, I dont know. This will help you for now.
To further generalise the answers given, here are a couple of macros (for 32-bit values; adjust for different bitfield lengths).
#include <stdio.h>
#include <stdint.h>
#define MASK(L,P) (~(0xffffffff << (L)) << (P))
#define GET_VAL(BF,L,P) (((BF) & MASK(L,P)) >> P)
#define SET_VAL(BF,L,P,V) ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) )
int main(int argc, char ** argv)
{
uint32_t bf = 1024;
printf("Bitfield before : %d , 0x%08x\n", bf, bf);
printf("Mask(5,3): %d , 0x%08x\n", MASK(5,3), MASK(5,3));
SET_VAL(bf,5,3,19);
printf("Bitfield after : %d , 0x%08x\n", bf, bf);
return 0;
}
As an aside, it's ridiculous that the C bitfield is completely useless. It's the perfect syntactic sugar for this requirement but due to leaving it up to each compiler to implement as it sees fit, it's useless for any real-world usage.

Working with 8-bit integers as flag masks

I have 65 different flags (options) for a custom data structure. Currently it looks like this:
struct CustomDataStruct {
int Something;
unsigned char Flags[9]
};
This way I'm able to store up to 72 flags (7 remaining, just in case I decide to add more). I want to use an individual bit for each flag, so I came up with this:
void SetFlag(struct CustomDataStructure* Struct, int FlagNr) {
// Error checking and other stuff here
int index = FlagNr / 8; array.
Struct->Flags[index] |= 1 << (__________);
}
I've already tried with 1 << (FlagNr % 8) but it's not setting the correct bit. For example, I want to turn on flag ID 23 (starting from zero), so I call SetFlag(structInstance, 23), which correctly determines the index (Flags[2]), but 23 % 8 = 7, and 1 << 7 = 1000 0000 (in binary), instead of the correct value, which should be 0000 0001(turn on last bit of the 3rd uchar of the array, i.e bit no. 24).
Flags must be stored on this array, each bit representing the flag switch. Changing this is not an option.
Bits are typically indexed starting from the least significant (rightmost) bit, since in most contexts that makes more sense. If you want to reverse that, just do 1 << (7 - FlagNr % 8) or 0x80 >> (FlagNr % 8).
Rather than doing a bit shift, an array lookup works easily. FlagNr contains the zero based bit index so a value of 0 is the first bit in the first array element.
void setFlag( struct CustomDataStructure* thing, int FlagNr) {
static uint8_t masks[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
size_t index = FlagNr % 8;
size_t xndex = FlagNr / 8;
thing->Flags[xndex] |= masks[index];
}
void setFlag( struct CustomDataStructure* foo, int flagIndex ) {
assert( flagIndex >= 0 && flagIndex < 72 ); // Defensive programming!
size_t arrayIndex = flagIndex / 8;
int bitShift = flagIndex % 8;
// If you want reverse (little-endian) bit order then subtract from 7:
bitShift = 7 - bitShift;
// This code is expanded for readability. An optimizing-compiler will still generate fast code:
uint8_t flags = foo->Flags[ arrayIndex ];
flags = flags | ( 1 << bitShift );
foo->Flags[ arrayIndex ] = flags;
}

binary sequence in uint8_t

I'm trying to create a table in "c" (for an embedded application) where each row is a sequence of 8 bits, for example:
11010011
01010011
10000000
then I need to have functions to set/clear/read any bit in any row. What is the most efficient way to do that?
For bit manipulation I thought to use:
uint8_t msk = 0x01;
row3 |= msk;
But to do this I think I need to define row3 (and every row) as uint8_t and convert it to hexadecimal as well, and that leads me to my second question:
how to store an 8-bit binary sequence in a uint8_t? I've seen different ways to do similar tasks like the one discussed here but none of them worked for me. Can you help me?
Thanks.
To represent binary bit patterns in C, it is normal to use hexadecimal notation. The utility of hex is that a single hex digit exactly coincides with 4 binary digits, so with experience you can quickly convert between the 16 hex digits and the corresponding binary value in your head, and for longer integers it is simply a matter of converting each digit in turn - 4 bits at a time. Representing long integers in binary quickly becomes impractical.
So your table might be represented as:
uint8_t row[] = { 0xd3, // 11010011
0x53, // 01010011
0x80 // 10000000
} ;
Then you set/clear bits in the following manner:
row[2] |= mask ; // Set mask bits
row[0] &= mask ; // Clear mask bits
To create a mask specifying numbered bits without hard-coding the hex value you can use an expression such as:
uint8_t mask = 1<<7 | 1<<5 | 1<<0 ; // 10100001 mask bits 0, 5 & 7
Occasionally a "visual" binary representation is desirable - for character bitmaps for example, the character A is much easier to visualise when represented in binary:
00000000
00011000
00100100
01000010
01111110
01000010
01000010
00000000
It is possible to efficiently code such a table while maintaining the "visualisation" by exhaustively defining a macro for each binary value; e.g:
#define B_00000000 0x00
#define B_00000001 0x01
#define B_00000010 0x02
#define B_00000011 0x03
#define B_00000100 0x04
...
#define B_11111110 0xfe
#define B_11111111 0xff
Note to create the above macros, it is best perhaps to write a code generator - i.e. a program to generate the code, and put the macros in a header file.
Given such macros you can then represent your table as:
uint8_t row[] = { B_11010011
B_01010011
B_10000000
} ;
or the character bitmap for A thus:
uint8_t charA[] = { B_00000000,
B_00011000,
B_00100100,
B_01000010,
B_01111110,
B_01000010,
B_01000010,
B_00000000 } ;
In the case that the bits are received at run-time serially, then the corresponding uint8_t can be built using sequential mask and shift:
uint8_t getByte()
{
uint8_t mask = 0x80 ;
uint8_y byte = 0 ;
while( mask != 0 )
{
uint8_t bit = getBit() ;
byte |= bit ? mask : 0 ;
mask >>= 1 ;
}
return byte ;
}
What the getBit() function does is for you to define; it may read a file, or a string, or keyboard entry for example, but it must return either zero or non-zero or the binary digits 0 and 1 respectively. If the data is received LSB first then the mask starts from 0x01, and a << shift used instead.
C doesn't have a syntax for entering binary literals, so you should type them as octal or hex, e.g.
uint8_t row1 = 0xd3;
uint8_t row2 = 0x53;
uint8_t row3 = 0x80;
See How do you set, clear, and toggle a single bit? for how you can manipulate specific bits.
row3 |= mask;
will set the bits that are set in mask.
If I understand correctly, you require a list of hexadecimal numbers and you would like to manipulate the bits in any of the elements of the list. I would approach it by making an array of unsigned integers with the size of the array being defined by the number of elements you need in your table.
#include <stdio.h>
#include <stdint.h>
#define LIST_SIZE 3
//accepts the array and sets bit_pos bit of the list idx
int set_bit(uint8_t* hex_list, int list_idx, int bit_pos){
hex_list[list_idx] = hex_list[list_idx] | 0x01<<bit_pos; //left shift by the bit position you want to set
}
int clear_bit(uint8_t* hex_list, int list_idx, int bit_pos){
hex_list[list_idx] = hex_list[list_idx] & ~(0x01<<bit_pos); //left shifts and does logical inversion to get the bit to clear
}
int main(void) {
uint8_t hex_list[LIST_SIZE] = {0x00, 0x01, 0x02};
set_bit(hex_list, 0, 1); // will make 0th element 0x00-> 0x02 by seting bit position 1
clear_bit(hex_list, 1,0); //will make 1st element 0x01-> 0x00 by clearing bit position 0
set_bit(hex_list, 2, 0); // will make 2nd element 0x02->0x03 by setting bit at position 1
clear_bit(hex_list, 2 , 0);// will make 2nd element 0x03 ->0x02 by clearing bit at position 0
//print the result and verify
for(int i = 0; i<LIST_SIZE; ++i){
// modified array will be {0x02, 0x00, 0x02}
printf("elem%d = %x \n", i, hex_list[i]);
}
return 0;
}
An uint8_t in represents a 8-bit unsigned integer whose value can vary between 0(binary representation = 00000000)to 255(binary representation = 11111111).

Bit rearrangement/manipulation in C

I want to arrange bits in a byte, to result in a certain order. For example, if the starting byte is as follows 0 1 1 0 1 0 1 0 with bits labeled as 1 2 3 4 5 6 7 8, I want to arrange it so it matches the following positioning: 2 4 3 5 7 1 8 6 this results to: 1 0 1 1 1 0 0 0. What would be the most efficient way of doing so? I read about "look-up" tables but I am not sure how this works. Can someone give an example and an explanation of an efficient way of doing this bit rearrangement in C.
You could create an array of "unsigned char" with 256 entries. The index into that array would be the current value of the byte to be converted, and the value at that entry would be the "converted" value.
Alternatively, you could use bit masking, and "if" statements... but it would less efficient.
Here's a snippet of the "array" method... with only a few values defined...
... and no output of the output in "binary-text" format.
#include<stdio.h>
unsigned char lkup[256] =
{ 0x00, /* idx: 0 (0x00) */
0x02, /* idx: 1 (0x01) (0b00000001) */
0x08, /* idx: 2 (0x02) (0b00000010) */
0x0a, /* idx: 3 (0x03) (0b00000011) */
0x01 /* idx: 4 (0x04) (0b00000100) */
};
int main(int argc, char **argv)
{
unsigned char wk = 3;
printf("Input: %u output: >%u\n", wk, lkup[wk]);
}
I think I understood what he wants to achieve. This code may help you:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint8_t original = 0b01101010;
uint8_t positions[8] = {1,3,2,4,6,0,7,5};
uint8_t result = 0;
for(int i = 0; i < 8; i++)
{
if(original & (1 << (7 - positions[i])))
result |= (1 << (7-i));
}
return 0;
}
The first thing I have done is to create a byte that represents the original value as well as a array of the positions you want to change. Next step ist to look the original byte at the xth. position is zero or one and then shift the value in the result if so. The last for-loop is just for printing the result.
I adjusted your indices to be zero-based.
Here is one way to change bit-positions. With & (and-operator) we select certain bits from the char and then shift them to new bit-positions. Finally all the shifted bits will happily join together by | (or-operator).
The left shift << will move bits left and right shift >> to the right. I took the freedom to renumber bit-positions. 7 means most-significant bit on the left and 0 is least-significant bit, so the left and right shift operations descripts shifting direction correctly.
And why there is the shift operations first and then AND-operation for the last two rows?
– Because char-type can be unsigned and if we do the right shift for the negative value, eg 11111000 (-8), the most-significant bit will be copied; 11111000 >> 2 will result (1 filled from this end -->) 11111110 (-2).
(See Right shifting negative numbers in C.)
But back into function:
char changebitpositions (char ch) {
// bit locations (- = don't care)
// before after
return (ch & 0x20) // --5----- => --5----- (no change)
| ((ch & 0x49) << 1) // -6--3--0 => 6--3--0-
| ((ch & 0x12) << 2) // ---4--1- => -4--1---
| ((ch >> 5) & 0x04) // 7------- => -----7--
| ((ch >> 2) & 0x01); // -----2-- => -------2
// original and result: 76543210 => 64531702
}

Resources