I'm working with a data stream of 8 bytes in an embedded application. In most cases the data is byte aligned so I can define a structure and then memcpy the data directly to the structure elements. There are, however, a few cases where the 16 bit data values span 2 or 3 bytes. I came up with a few macros to handle these cases. It's working fine, but I'm wondering if anyone can point out some obvious flaws or code optimizations to make the macros more efficient.
The sample code is:
The output of the sample is:
The sample code is:
Code:
//------------------------------------------------------------------------------------------------------------------------------------------------ // M_EXTRACT // This macro extracts a value from within a block of memory. The value extracted starts from and includes the start bit and ends with the // end bit. The first bit is bit 0. The maximum number of bits for a value is 16. //------------------------------------------------------------------------------------------------------------------------------------------------ #include <stdio.h> #define M_EXTRACT16(sbit, ebit, data) ( (M_BYTENUM(sbit)) == (M_BYTENUM(ebit)) ? M_EXTRACT_1(sbit, ebit, data) : ( (M_BYTENUM(ebit)) - (M_BYTENUM(sbit)) == 1) ? M_EXTRACT_2(sbit, ebit, data) : M_EXTRACT_3(sbit, ebit, data) ) #define M_BYTENUM(x) (x>>3) // Determine which byte the bit resides in #define M_BYTEVAL(x) ( M_BYTENUM(x) << 3 ) // Determine starting bit 0 for a given byte... for example bit 0 of byte 2 is bit 16 in the data set. #define M_EXTRACT_1(sbit, ebit, data) ( M_LOW(sbit, data) & ( (1 << (ebit - sbit + 1)) - 1) ) // If start & end are within one byte, use this. #define M_EXTRACT_2(sbit, ebit, data) ( M_LOW(sbit, data) | M_HIGH(sbit, ebit, data) ) // If start & end span 2 bytes, use this. #define M_EXTRACT_3(sbit, ebit, data) ( M_LOW(sbit, data) | M_MID(sbit, data) | M_HIGH(sbit, ebit, data) ) // if start & end span three bytes, use this. #define M_HIGH(sbit, ebit, data) ( (data[M_BYTENUM(ebit)] & ( (1<<(ebit - M_BYTEVAL(ebit) + 1)) - 1 ) ) << (( M_BYTEVAL(ebit) - sbit)&0x0f ) ) // Upper portion of value #define M_MID(sbit, data) ( data[M_BYTENUM(sbit)+1] << ((M_BYTEVAL(( M_BYTENUM(sbit)+1 )) - sbit )&0x0f) ) // Middle byte value when value spans three bytes #define M_LOW(sbit, data) ( data[M_BYTENUM(sbit)] >> ((sbit - M_BYTEVAL(sbit))&0x0f) ) // Lower portion of value void main() { unsigned int i, sb, eb; unsigned char d[8]; d[0] = 0xa7; d[1] = 0xc2; d[2] = 0xd6; d[3] = 0xe6; d[4] = 0xa3; d[5] = 0x5a; d[6] = 0xa5; d[7] = 0x1c; sb = 0; eb = 4; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 10; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 22; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 29; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 30; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 43; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 50; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 60; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); sb = eb+1; eb = 63; i = M_EXTRACT16( sb, eb, d); printf("sb = %02d | eb = %02d | i = %d\n", sb, eb, i); }
Code:
sb = 00 | eb = 04 | i = 7 sb = 05 | eb = 10 | i = 21 sb = 11 | eb = 22 | i = 2776 sb = 23 | eb = 29 | i = 77 sb = 30 | eb = 30 | i = 1 sb = 31 | eb = 43 | i = 5447 sb = 44 | eb = 50 | i = 85 sb = 51 | eb = 60 | i = 916 sb = 61 | eb = 63 | i = 0
Comment