This question already has answers here:
How do I set, clear, and toggle a single bit?
(27 answers)
Closed 2 years ago.
I'm trying to write a C function that takes a uint64_t and replace it's nth byte to a given one.
void setByte(uint64_t *bytes, uint8_t byte, pos)
I know I can easily get the nth byte like so
uint8_t getByte(uint64_t bytes, int pos)
{
return (bytes >> (8 * pos)) & 0xff;
}
But I have no idea how to Set the nth byte
Try this:
void setByte(uint64_t *bytes, uint8_t byte, int pos) {
*bytes &= ~((uint64_t)0xff << (8*pos)); // Clear the current byte
*bytes |= ((uint64_t)byte << (8*pos)); // Set the new byte
}
Use a mask to set every bit of the target byte to 0 (i.e. the mask should be all 1s but 0s at the target byte and then ANDed to the integer), then use another mask with all 0s but the intended value in the target byte and then OR it with the integer.
Related
I'm trying to convert numbers to binary and then fwrite the binary numbers to binary file.
Assuming all numbers are 7 bits numbers (int numbers < 127).
So in the end, the file will contain the numbers as blocks of 7 bits
I know that each BYTE is 8 bits, and i can't to write each number to 1 BYTE, but need to use the whole BYTE (i.e some of the numbers will be in 2 different BYTES)
if : 120 = 1111000 | 7 = 0000111 | 64 = 1000000
so the bit stream is 111100000001111000000 and should be written as
1111000|0 000111|10 00000|00
1BYTE 2BYTE 3BYTE
I thought to use a buffer
shifting 8 bits to buffer and then fwrite to the file, using pointers
But i just can't mange to write it. Thank you for your help
First, when dealing with bits use unsigned integers
unsigned char a = 0;
char bits[] = "1111000";
char *p = bits;
while (*p) {
a <<= 1; // shift left
a |= (*p == '1'); // add bit
p++; // next bit
}
So, you want to put 8 7-bit values in 7 8-bit locations
[-val-][-val-][-val-]...
00000001111111222222233333334444444555555566666667777777
[-loc8-][-loc8-][-loc8-]...
Just map bits and you're done
For example, the 3rd 7-bit value (assuming int val7[8]) can be written into the 8-bit locations (assuming int loc8[7]) with
loc8[1] &= 0xfc; // clear 2 bits
loc8[1] |= (val7[2] & 0x60) >> 5; // set 2 bits
loc8[2] &= 0x7; // clear 5 bits
loc8[2] |= (val7[2] & 0x1f) << 3; // set 5 bits
I want to read binary file byte at the time and then store bits of that byte into integer array. And similarly I want to write integer array of 1s and 0s (8 of them ) into binary file as bytes?
If you have an array of bytes:
unsigned char bytes[10];
And want to change it into an array of bits:
unsigned char bits[80];
And assuming you have 8 bits per byte, try this:
int i;
for (i=0; i<sizeof(bytes)*8; i++) {
bits[i] = ((1 << (i % 8)) & (bytes[i/8])) >> (i % 8);
}
In this loop, i loops through the total number of bits. The byte that a given bit lives at is i/8, which as integer division rounds down. The position of the bit within a byte is i%8.
First we create a mask for the desired bit:
1 << (i % 8)
Then the desired byte:
bytes[i/8]
Then we perform a logical AND to clear all bits except the one we want.
(1 << (i % 8)) & (bytes[i/8])
Then we shift the result right by the bit position to put the desired bit at the least significant bit. This gives us a value of 1 or 0.
Note also that the arrays in question are unsigned. That is required for the bit shifting to work properly.
To switch back:
int i;
memset(bytes, 0, sizeof(bytes));
for (i=0; i<sizeof(bytes)*8; i++) {
bytes[i/8] |= bits[i] << (i % 8);
}
We start by clearing out the byte array, since we'll be setting each byte one bit at a time.
Then we take the bit in question:
bits[i]
Shift it into its position:
bits[i] << (i % 8)
Then use a logical OR to set the appropriate byte;
A simple C program to do the job on a byte array 'input' of size 'sz' would be:
int i=0,j=0;
unsigned char mask = 0x01u;
for (i=0;i<sz;i++)
for (j=0;j<8;j++)
output[8*i+j]=((unsigned char)input[i] >> j) & (unsigned char)(mask);
I would to implement a function like this:
int read_single_bit(unsigned char* buffer, unsigned int index)
where index is the offset of the bit that I would want to read.
How do I use bit shifting or masking to achieve this?
You might want to split this into three separate tasks:
Determining which char contains the bit that you're looking for.
Determining the bit offset into that char that you need to read.
Actually selecting that bit out of that char.
I'll leave parts (1) and (2) as exercises, since they're not too bad. For part (3), one trick you might find useful would be to do a bitwise AND between the byte in question and a byte with a single 1 bit at the index that you want. For example, suppose you want to get the fourth bit out of a byte. You could then do something like this:
Byte: 11011100
Mask: 00001000
----------------
AND: 00001000
So think about the following: how would you generate the mask that you need given that you know the bit index? And how would you convert the AND result back to a single bit?
Good luck!
buffer[index/8] & (1u<<(index%8))
should do it (that is, view buffer as a bit array and test the bit at index).
Similarly:
buffer[index/8] |= (1u<<(index%8))
should set the index-th bit.
Or you could store a table of the eight shift states of 1 and & against that
unsigned char bits[] = { 1u<<0, 1u<<1, 1u<<2, 1u<<3, 1u<<4, 1u<<5, 1u<<6, 1u<<7 };
If your compiler doesn't optimize those / and % to bit ops (more efficient), then:
unsigned_int / 8 == unsigned_int >> 3
unsigned_int % 8 == unsigned_int & 0x07 //0x07 == 0000 0111
so
buffer[index>>3] & (1u<<(index&0x07u)) //test
buffer[index>>3] |= (1u<<(index&0x07u)) //set
One possible implementation of your function might look like this:
int read_single_bit(unsigned char* buffer, unsigned int index)
{
unsigned char c = buffer[index / 8]; //getting the byte which contains the bit
unsigned int bit_position = index % 8; //getting the position of that bit within the byte
return ((c >> (7 - bit_position)) & 1);
//shifting that byte to the right with (7 - bit_position) will move the bit whose value you want to know at "the end" of the byte.
//then, by doing bitwise AND with the new byte and 1 (whose binary representation is 00000001) will yield 1 or 0, depending on the value of the bit you need.
}
This question already has answers here:
How do I set, clear, and toggle a single bit?
(27 answers)
Closed 7 years ago.
I wish to store either 0 or 1 in each bit of an allocated memory. For example I have char *block_of_memory = (char *)malloc(125000 * sizeof(char)) , here I have 125000 * 8 bits = 1000,000 bits of memory. How can I access each bit and give it a value as 0 or 1. Say , I want to make the 20th bit to 1 and 21st bit as 0.
You need to calculate a byte offset and a bitmask within that byte.
Set the bit: bitwise OR with mask
Clear the bit: bitwise AND with complement of mask
Read the bit: return bitwise AND of byte and mask
The code:
void set_bit(char *buf, int bit, int val)
{
int byte = bit / 8;
char mask = 1 << (bit % 8);
if (val)
buf[byte] |= mask;
else
buf[byte] &= ~mask;
}
int get_bit(char *buf, int bit)
{
int byte = bit / 8;
char mask = 1 << (bit % 8);
return buf[byte] & mask ? 1 : 0;
}
Example: Set bit 17 to 1. Byte offset is 17/8 = 2. Bit offset is 17%8 = 1. The bitmask is generated by left-shifting 1 by the bit offset: results in 00000010 binary. Bitwise OR byte[2] with it: all bits remain the same, except where the mask bit is 1.
There's a variable:
char segment = 0;
After 1 or with bit 15, segment = 1;
Just means this bit check already.
Question is how to cancel the mark of bit 15 (set back to 0)?
Use "~"?
Following program sets bit, clears bit and toggles bit
#include<stdio.h>
void main(void)
{
unsigned int byte;
unsigned int bit_position;
unsigned int tempbyte = 0x01;
//get the values of the byte and the bit positions
//set bit
byte = (byte | (tempbyte << bit_position));// set the bit at the position given by bit_position
//clear bit
byte = (byte & ~(tempbyte << bit_position));//clear the bit at the position given by bit_position
//toggle bits
byte = (byte ^ (tempbyte << bit_position));//toggle the bit at the position given by bit_position
}
To get rid of the MSB of an 8-bit character for example, you can AND with 0x7F
e.g. segment = segment & 0x7F;
To dynamically produce the mask, you can use bit shifting operations (i.e. the << operator).