How to store two different things in one byte and then access them again? - c

I am trying to learn C for my class. One thing I need to know is given an array, I have to take information from two characters and store it in one bytes. For eg. if string is "A1B3C5" then I have to store A = 001 in higher 3bits and then store 1 in lower 5bits. I have to function that can get two chars from array at a time and print it here is that function,
void print2(char string[])
{
int i = 0;
int length = 0;
char char1, char2;
length = strlen(string);
for ( i = 0; i <length; i= i + 2)
{
char1 = string[i];
char2 = string[i+1];
printf("%c, %c\n", char1, char2);
}
}
but now i am not sure how to get it encoded and then decode again. Can anyone help me please?

Assuming an ASCII character set, subtract '#' from the letter and shift left five bits, then subtract '0' from the character representing the digit and add it to the first part.

So you've got a byte, and you want the following bit layout:
76543210
AAABBBBB
To store A, you would do:
unsigned char result;
int input_a = somevalue;
result &= 0x1F; // Clear the upper 3 bits.
// Store "A": make sure only the lower 3 bits of input_a are used,
// Then shift it by 5 positions. Finally, store it by OR'ing.
result |= (char)((input_a & 7) << 5);
To read it:
// Simply shift the byte by five positions.
int output_a = (result >> 5);
To store B, you would do:
int input_b = yetanothervalue;
result &= 0xE0; // Clear the lower 5 bits.
// Store "B": make sure only the lower 5 bits of input_b are used,
// then store them by OR'ing.
result |= (char)(input_b & 0x1F);
To read it:
// Simply get the lower 5 bits.
int output_b = (result & 0x1F);
You may want to read about the boolean operations AND and OR, bit shifting and finally bit masks.

First of all, one bit can only represent two states: 0 and 1, or TRUE and FALSE. What you mean is a Byte, which consists of 8 bits and can thus represent 2^8 states.
Two put two values in one byte, use logical OR (|) and bitwise shift (<< and >>).
I don't post the code here since you should learn this stuff - it's really important to know what bits and bytes are and how to work with them. But feel free to ask follow up question if something is not clear to you.

Related

How do you incorporate variables into a bit mask?

I have a particular byte where each bit in the byte depends on some other value or information. In particular, one byte is formatted as follows:
Bits 1-3 = 011
Bits 4-7 = binary value of char at that position
Bit 8 = 1 or 0 depending on a 2nd parameter
Thus, I thought I might replace code like:
if (last == TRUE) {
callsign[j] = 0b01100001;
} else {
callsign[j] = 0b01100000;
}
with the simple two-liner:
char mask[];
sprintf("%s%i", 0b1111111, last);
callsign[j] = 0b01100001 & mask;
Unfortunately, that didn't work, generating a ton of errors, among them an Attempt to create a pointer to a constant, which I can't decipher.
Essentially, either way, I need to create a byte composed of individual bits or groups of bits in a specific order. Inevitably, they will be variables, and somehow I need to concatenate them into a byte.
I was thinking masks would be the way to go, but even if I opt for a mask, I somehow need to concatenate a parameter into the mask.
What's the best way to go about this? Using masks seems convenient, but how can I create a mask by combining variables with binary?
You can toggle bits using the "or" | and "and" & operator.
uint8_t some_byte = 0b10000000;
some_byte |= 0b00100000;
// Result: 0b10100000.
some_byte = 0b10000011;
some_byte &= 0b01111111;
// Result: 0b00000011.

How to handle a bunch of 0s and 1s with a microcontroller?

I'm making a program to receive a bunch of 0's and 1's with a µC and need to take any amount of bits (1 to 16) from any position.
I.E. I have 150 bits and I want to take 6 bits from the 32th bit and copy it to a char (8bits) variable; I know I can do it with strings by saving as ASCII 0's and 1's, but I have not a lot of RAM, so I need to save it as bits.
The bigger variable is a unsigned 32 bits long, but save the data is not my problem, the problem is how to access to a specific bits positions and copy that to a char(8) variable.
You can use bitwise operators:
//bits: your bits (byte array), start: index of the first bit of the char you want
char select(char* bits, int start) {
dec = start%8;
return bits[start/8]>>dec + bits[start/8+1]<<dec;
}
The code above supposed start < (bits.size()-8)
[EDIT]
You can change the char* to any type you want. However you will need to change dec value to the appropriate number of bits (8*SIZE_IN_BYTES) and then apply operator | ("logical or") to get your char back
example:
char select(int* bits, int start) {
nbitsint = 8*4;
dec = start%nbitsint;
if (dec < nbitsint-8) {
// | 0xff creates creates a byte
return (bits[start/nbitsint]>>((3-dec/8)*8+dec%8) | 0xff;
}
// Getting a byte which is astride two values is tricky
return (bits[start/nbitsint]>>(start%8) + bits[start/nbitsint+1]<<(start%8) | 0xff;
}

Read a single bit from a buffer of char

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.
}

String to very long sequence of length less than 1 byte

I can't guess how to solve following problem. Assume I have a string or an array of integer-type variables (uchar, char, integer, whatever). Each of these data type is 1 byte long or more.
I would like to read from such array but read a pieces that are smaller than 1 byte, e.g. 3 bits (values 0-7). I tried to do a loop like
cout << ( (tab[index] >> lshift & lmask) | (tab[index+offset] >> rshift & rmask) );
but guessing how to set these variables is out of my reach. What is the metodology to solve such problem?
Sorry if question has been ever asked, but searching gives no answer.
I am sure this is not the best solution, as there some inefficiencies in the code that could be eliminated, but I think the idea is workable. I only tested it briefly:
void bits(uint8_t * src, int arrayLength, int nBitCount) {
int idxByte = 0; // byte index
int idxBitsShift = 7; // bit index: start at the high bit
// walk through the array, computing bit sets
while (idxByte < arrayLength) {
// compute a single bit set
int nValue = 0;
for (int i=2; i>=0; i--) {
nValue += (src[idxByte] & (1<<idxBitsShift)) >> (idxBitsShift-i);
if ((--idxBitsShift) < 0) {
idxBitsShift=8;
if (++idxByte >= arrayLength)
break;
}
}
// print it
printf("%d ", nValue);
}
}
int main() {
uint8_t a[] = {0xFF, 0x80, 0x04};
bits(a, 3, 3);
}
The thing with collecting bits across byte boundaries is a bit of a PITA, so I avoided all that by doing this a bit at a time, and then collecting the bits together in the nValue. You could have smarter code that does this three (or however many) bits at a time, but as far as I am concerned, with problems like this it is usually best to start with a simple solution (unless you already know how to do a better one) and then do something more complicated.
In short, the way the data is arranged in memory strictly depends on :
the Endianess
the standard used for computation/representation ( usually it's the IEEE 754 )
the type of the given variable
Now, you can't "disassemble" a data structure with this rationale without destroing its own meaning, simply put, if you are going to subdivide your variable in "bitfields" you are just picturing an undefined value.
In computer science there are data structure or informations structured in blocks, like many hashing algorithms/hash results, but a numerical value it's not stored like that and you are supposed to know what you are doing to prevent any data loss.
Another thing to note is that your definition of "pieces that are smaller than 1 byte" doesn't make much sense, it's also highly intrusive, you are losing abstraction here and you can also do something bad.
Here's the best method I could come up with for setting individual bits of a variable:
Assume we need to set the first four bits of variable1 (a char or other byte long variable) to 1010
variable1 &= 0b00001111; //Zero the first four bytes
variable1 |= 0b10100000; //Set them to 1010, its important that any unaffected bits be zero
This could be extended to whatever bits desired by placing zeros in the first number corresponding to the bits which you wish to set (the first four in the example's case), and placing zeros in the second number corresponding to the bits which you wish to remain neutral in the second number (the last four in the example's case). The second number could also be derived by bit-shifting your desired value by the appropriate number of places (which would have been four in the example's case).
In response to your comment this can be modified as follows to accommodate for increased variability:
For this operation we will need two shifts assuming you wish to be able to modify non-starting and non-ending bits. There are two sets of bits in this case the first (from the left) set of unaffected bits and the second set. If you wish to modify four bits skipping the first bit from the left (1 these four bits 111 for a single byte), the first shift would be would be 7 and the second shift would be 5.
variable1 &= ( ( 0b11111111 << shift1 ) | 0b11111111 >> shift2 );
Next the value we wish to assign needs to be shifted and or'ed in.
However, we will need a third shift to account for how many bits we want to set.
This shift (we'll call it shift3) is shift1 minus the number of bits we wish to modify (as previously mentioned 4).
variable1 |= ( value << shift3 );

Easy way to convert a string of 0's and 1's into a character? Plain C

I'm doing a steganography project where I read in bytes from a ppm file and add the least significant bit to an array. So once 8 bytes are read in, I would have 8 bits in my array, which should equal some character in a hidden message. Is there an easy way to convert an array of 0's and 1's into an ascii value? For example, the array: char bits[] = {0,1,1,1,0,1,0,0} would equal 't'. Plain C
Thanks for all the answers. I'm gonna give some of these a shot.
A simple for loop would work - something like
unsigned char ascii = 0;
unsigned char i;
for(i = 0; i < 8; i++)
ascii |= (bits[7 - i] << i);
There might be a faster way to do this, but this is a start at least.
I wouldn't store the bits in an array -- I'd OR them with a char.
So you start off with a char value of 0: char bit = 0;
When you get the first bit, OR it with what you have: bit |= bit_just_read;
Keep doing that with each bit, shifting appropriately; i.e., after you get the next bit, do bit |= (next_bit << 1);. And so forth.
After you read your 8 bits, bit will be the appropriate ASCII value, and you can print it out or do whatever with it you want to do.
I agree with mipadi, don't bother storing in an array first, that's kind of pointless. Since you have to loop or otherwise keep track of the array index while reading it in, you might as well do it in one go. Something like this, perhaps?
bits = 0;
for ( i = 0; i < 8; ++i ) {
lsb = get_byte_from_ppm_somehow() & 0x01;
bits <<= 1 | lsb;
}
As long as the bit endian is correct, this should work and compile down pretty small.
If the bit endian is backwards then you should be able to change the initial value of mask to 1, the mask shift to <<= , and you might need to have (0x0ff & mask) as the do{}while conditional if your compiler doesn't do what it's supposed to with byte sized variables.
Don't forget to do something for the magic functions that I included where I didn't know what you wanted or how you did something
#include <stdint.h> // needed for uint8_t
...
uint8_t acc, lsb, mask;
uint8_t buf[SOME_SIZE];
size_t len = 0;
while (is_there_more_ppm_data()) {
acc = 0;
mask = 0x80; // This is the high bit
do {
if (!is_there_more() ) {
// I don't know what you think should happen if you run out on a non-byte boundary
EARLY_END_OF_DATA();
break;
}
lsb = 1 & get_next_ppm_byte();
acc |= lsb ? mask : 0; // You could use an if statement
mask >>= 1;
} while (mask);
buf[len] = acc; // NOTE: I didn't worry about the running off the end of the buff, but you should.
len++;
}

Resources