Dear comp.lang.c members,
I have the following problem:
I am writing an application which reads data from a device. This data
is 12 bit wide and comes as a stream of words to be stored to a file.
At the moment I write it to 16 bit words, which creates an unessecary
overhead.
I currently use uint16_t.
How may I do this?
It depends on what you need to do with the data. If all you need is to
read it and then write it to somewhere else, you can just use unsigned
char[] (i.e., "bytes") and be done with it.
But if you need to perform arithmetic operations on the 12-bit
integers, for example, you can still use unsigned char[] to hold the
data and then copy individual 12-bit units into uint16_t variables to
perform the desired operations:
unsigned char* data;
size_t len;
ReadDeviceData(&data, &len);
// Fetch the first 12-bit unit and store it in a uint16_t
uint16_t num = *(uint16_t*) data >> 4;
(Your program may need to take byte ordering into account.) You may
write a macro to fetch a 12-bit value that is at a specific "bit
offset":
//
// Returns a 12-bit unit as a uint16_t
//
// @param offset the bit offset of the 12-bit value; must be
// a multiple of 12
// @param ptr a pointer to the block of memory
//
#define GET_UNIT(offset, ptr) \
(*(uint16_t*) ((ptr) + (offset) / CHAR_BIT) >> \
4 - (offset) % CHAR_BIT & \
~0U >> (offset) % CHAR_BIT)
Using such a macro you could step through every 12-bit value in an
arbitrary block of memory (unsigned char[]). For example, this loop
would print all 12-bit values as decimal numbers:
for (size_t offset = 0; offset + 12 < len * CHAR_BIT; offset +=
12)
printf("%" PRIu16 "\n", GET_UNIT(offset, data));
The point is that now you're using an array of unsigned char to hold
the data (thus saving space), and then copying individual 12-bit
values into uint16_t variables whenever you need to perform an
operation on them.
Sebastian