Base on this question. I would like to store elements of arbitrary site, e.g., 5-bit, into an array of unsigned char.
My none working solution is based on the answer of @KamilCuk which is specific for 4-bit elements. The example below works for any bits, but only the first byte of the array. I know, that I have to change t[0]
to t[1]
once I want to write into the next byte. But when I write e.g. 5 bits each time, the 2nd write should write 3 bit in the first byte amd two into the 2nd byte (0x1F00
to 0xFF03
). A dirty workaround would be to change uint8_t *t
to something like uint32_t *t
but this would only postpone the problem until you want to write more than 32 bit.
Can you think of a more clever way to write an arbitrary bit size element into an array of unsigned char without any padding?
#include <stdio.h>
#include <stdint.h>
#include <string.h>
# define VALUE_1_SIZE_BITS 2
# define VALUE_2_SIZE_BITS 3
# define FREE_BYTES 5
struct delta_measurement_struct {
unsigned delta_time: VALUE_1_SIZE_BITS;
unsigned delta_sensor_data: VALUE_2_SIZE_BITS;
} __attribute__((packed)); // avoid structure padding
void data_struct_array_set(uint8_t *t, unsigned idx, struct delta_measurement_struct delta_measurement) {
const unsigned v = delta_measurement.delta_time << VALUE_2_SIZE_BITS | delta_measurement.delta_sensor_data;
const unsigned mask = (VALUE_1_SIZE_BITS + VALUE_2_SIZE_BITS) * idx;
// const unsigned mask = (VALUE_1_SIZE_BITS + VALUE_2_SIZE_BITS) * ((VALUE_1_SIZE_BITS + VALUE_2_SIZE_BITS) * idx / 8);
t[0] |= v << mask;
}
int main() {
uint8_t delta_measurements[FREE_BYTES];
memset(&delta_measurements, 0, sizeof(delta_measurements));
for (int i = 0; i < ((FREE_BYTES * 8) / (VALUE_1_SIZE_BITS + VALUE_2_SIZE_BITS)); ++i) {
printf("set %d bits\n", (VALUE_1_SIZE_BITS + VALUE_2_SIZE_BITS));
data_struct_array_set(delta_measurements, i, (struct delta_measurement_struct) {3, 7});
printf("union_data = 0x");
for (int j = 0; j < FREE_BYTES; ++j) {
printf("%02X-", delta_measurements[j]);
}
printf("\n");
}
return 0;
}