c++; Is bitset the solution for me? - c++

I am writing a program and using memcpy to copy some bytes of data, using the following code;
#define ETH_ALEN 6
unsigned char sourceMAC[6];
unsigned char destMAC[6];
char* txBuffer;
....
memcpy((void*)txBuffer, (void*)destMAC, ETH_ALEN);
memcpy((void*)(txBuffer+ETH_ALEN), (void*)sourceMAC, ETH_ALEN);
Now I want to copy some data on to the end of this buffer (txBuffer) that is less than a single byte or greater than one byte, so it is not a multiple of 8 (doesn't finish on a whole byte boundary), so memcpy() can't be used (I don't believe?).
I want to add 16 more bits worth of data which is a round 4 bytes. First I need to add a value into the next 3 bits of txtBuffer which I have stored in an int, and a fourth bit which is always 0. Next I need to copy another 12 bit value, again I have this in an int.
So the first decimal value stored in an int is between 0 and 7 inclusively, the same is true for the second number I mention to go into the final 12 bits. The stored value is within the rang of 2^12. Should I for example 'bit-copy' the last three bits of the int into memory, or merge all these values together some how?
Is there a way I can compile these three values into 4 bytes to copy with memcpy, or should I use something like bitset to copy them in, bit at a time?
How should I solve this issue?
Thank you.

Assuming int is 4 bytes on your platform
int composed = 0;
int three_bits = something;
int twelve_bits = something_else;
composed = (three_bits & 0x07) | (1 << 3) | ((twelve_bits << 4) & 0xFFFFFF0);

Related

Can i store 2 * 12bit unsigned numbers in a file as 3 bytes in C++ using bit fields?

I`m working on an LZW compression app in C++. Since there are no data types that can store 12 bit numbers for representing table elements up to 4095 I thought that I can store 2 of those nrs as 3 bytes in a file and then read them as a struct with 2 unsigned short members. Is there a way to do that or I should just use unsigned short? This is what I have tried but it stores 4 bytes as there are 2 unsigned short members.
#define BITS 12
struct LZWStruct {
unsigned short code1 : BITS;
unsigned short code2 : BITS;
};
int main() {
LZWStruct test;
test.code1 = 144;
test.code2 = 233;
FILE* f = fopen("binary.bin", "wb");
fwrite(&test, sizeof(test), 1, f);
fclose(f);
}
Your question title and question body are two different questions with different answers.
No, you absolutely cannot store 3 * 12-bit unsigned numbers (36 bits) in four bytes (32 bits).
Yes, you can store two 12-bit numbers (24 bits) in three bytes (24 bits).
The bit fields in C++, inherited from C, that you are trying to use do not guarantee exactly how the bits are packed in the structure, so you cannot know which three bytes in the structure have your data. You should simply use the shift and or operators to put them in an integer. Then you will know exactly which three bytes to write to the file.
Then to be portable, in particular not dependent on the endianess of the machine, you should write bytes from the integer also using the shift operator. If you write using a pointer to the integer, it won't be portable.
In your example, you could have tried fwrite(&test, 3, 1, f), and it might work, if the compiler put the codes in the low bits of test, and if your machine is little-endian. Otherwise, no.
So to do it reliably:
Put in an integer:
unsigned short code1;
unsigned short code2;
uint32_t test = (code1 & 0x3ff) | ((uint32_t)(code2 & 0x3ff) << 12);
Write to a file:
putc(test, f);
putc(test >> 8, f);
putc(test >> 16, f);
You can skip the intermediate step if you like:
putc(code1, f);
putc(((code1 >> 8) & 0xf) | (code2 << 4), f);
putc(code2 >> 4, f);
(In the above I am assuring that I only store the low 12 bits of each code with the & operators, in case the bits above the low 12 are not zero. If you know for certain that the code values are less than 4096, then you can remove the & operations above.)
From here, multiple adjacent bit fields are usually packed together. The special unnamed bit field of size zero can be forced to break up padding. It specifies that the next bit field begins at the beginning of its allocation unit. Use sizeof to verify the size of your structure.
The exact packing, however, may depend on platform and compiler. This may be less a problem if the data are later loaded by the same program, or some closely related, but may be an issue for some generic format.

Bits to type from buffer

A file which contains the buffer value. The first 16 bits contain the type. The next 32 bits gives the length of the data. The remaining value in the data.
How can I find the type from the 16 bits (find if it is int or char...)
I'm super stuck in my though process here. Not able to find a way to convert bits to types.
Say you have the homework assignment:
You are given a file where the first bit encodes the type, the
next 7 bits encode the length, and the rest is the data.
The types are encoded in the following way:
0 is for int
1 is for char
Print the ints or chars separated by newlines.
You just use the given information! Since 1 bit is used to encode the type there are two possible types. So you just read the first bit, then do:
if (bit == 0) {
int *i = ...
}
else if (bit == 1) {
char *c = ...
}

How can i store 2 numbers in a 1 byte char?

I have the question of the title, but If not, how could I get away with using only 4 bits to represent an integer?
EDIT really my question is how. I am aware that there are 1 byte data structures in a language like c, but how could I use something like a char to store two integers?
In C or C++ you can use a struct to allocate the required number of bits to a variable as given below:
#include <stdio.h>
struct packed {
unsigned char a:4, b:4;
};
int main() {
struct packed p;
p.a = 10;
p.b = 20;
printf("p.a %d p.b %d size %ld\n", p.a, p.b, sizeof(struct packed));
return 0;
}
The output is p.a 10 p.b 4 size 1, showing that p takes only 1 byte to store, and that numbers with more than 4 bits (larger than 15) get truncated, so 20 (0x14) becomes 4. This is simpler to use than the manual bitshifting and masking used in the other answer, but it is probably not any faster.
You can store two 4-bit numbers in one byte (call it b which is an unsigned char).
Using hex is easy to see that: in b=0xAE the two numbers are A and E.
Use a mask to isolate them:
a = (b & 0xF0) >> 4
and
e = b & 0x0F
You can easily define functions to set/get both numbers in the proper portion of the byte.
Note: if the 4-bit numbers need to have a sign, things can become a tad more complicated since the sign must be extended correctly when packing/unpacking.

C++ bitset with if statement

I was wondering if there is anyway to use specific range of bits with if statement.
im using a fpga to send 8bits binary data over usb to pc. each transaction has 3x 8 bits packets. in each packet first four bits are generated by outside module and i want to send control data in the last four bits.
=>
usb interface accepts data as integers and i've got bitset function to convert integers to 8bit binary. i want to use last four bits to use with if statements. is there any way i can do this?
thanks in advance
If you have an unsigned char as input:
void foo(uint8_t x) {
uint8_t top4 = x >> 4; // moves top 4 bits down by 4 positions
uint8_t bottom4 = x & 0x0f; // zeros out top 4 bits, leaving bottom 4
}
This will work with int, short, etc., types as well, but you would need to &-mask the top results too to strip away the unwanted high bits there.

Assign large type variable to a smaller types array

I am just wondering how this works, and to be clear as to whether it actually does work.
If you have a 32 bit int and an 8 bit int array of size 4. Can you assign the 32 bit int to the 0th index in the 8 bit int array and effectively have the same value, bit wise.
Also if you then wanted to convert it back I presume you could fill up the 32 bit int with the array and appropriate bit shifts.
int32 bigVbl = 20;
int8 smallVbl[4];
smallVbl[0] = bigVbl;
I expect the smallVbl array to hold the entirety of bigVbl.
Assignments always truncate the most significant bits and retain the LSBs. Other arithmetics operations truncate the result too, if it overflows. In that way you can extend the maths (and many other operations) for operating on big integers easily. Without truncation how can you crammed 32 bits into 8 bits?
To copy the 32-bit int into an array of 4 8-bit chars, the easiest ways is copy the whole number into the array. Another way is assign element-by-element
smallVbl[0] = bigVbl & 0xff; // the & 0xff is not really needed
smallVbl[1] = (bigVbl >> 8) & 0xff;
smallVbl[2] = (bigVbl >> 16) & 0xff;
smallVbl[3] = (bigVbl >> 24) & 0xff;
There are a couple of ways of doing it, the simplest probably being to use std::copy_n to copy the integer into the array:
std::copy_n(reinterpret_cast<int8*>(&bigVbl), // Source to copy from
std::min(sizeof(smallVbl), sizeof(bigVbl)), // Number of bytes to copy
smallVbl); // Destination to copy to
To copy the opposite direction, just switch place of the source and destination in the above call.