I very much dislike dealing with cross-platform endian issues. When it comes to defining structures with bitfields–it can sometimes become a pain to order all the fields correctly depending on the platform one is using.
Another headache is dealing with host byte ordering and network traffic on Intel platforms–all that byte swapping!!!
Anyway, I’ve been using some simple functions that allow me to parse the message on the fly while it is still in network byte order with no need for byte swapping or structures with bitfields.
The great thing about this code is that it is cross-platform; absolutely no endian issues to deal with. The price paid for this portability is execution speed–this code will likely be slower when parsing many fields out of a large message. But if you only need one or two fields from a large message, then this code will actually be faster than byte swapping the entire message.
Below you will find the bitfield extract code header file, then give a small sample program which uses it, and its corresponding output.
Here’s the bitfieldextract.h
header file:
#ifndef __BITFIELDEXTRACT_H__ #define __BITFIELDEXTRACT_H__ #if !defined(WIN32) typedef unsigned long UINT32; typedef unsigned short UINT16; typedef unsigned char UCHAR; typedef unsigned char *PUCHAR; typedef char *PCHAR; #else #include#endif /* // // bfx -- bit field extract // // extract up to a 32-bit value at any bit // offset in a byte array // */ inline UINT32 bfx( const PUCHAR cptr, UINT32 bit_offset, UINT32 bit_len) { /* // Portable bit field extract code */ UINT32 byte_off = ( bit_offset >> 3 ); UINT32 left_shift = bit_offset - ( byte_off << 3 ); UINT32 bytes = ( left_shift + bit_len + 7 ) >> 3; UINT32 right_shift = ( bytes << 3 ) - ( bit_len + left_shift ); UINT8 cval; UINT32 val, i; /* grab first byte and apply shift */ cval = cptr[byte_off] << left_shift; val = cval; bytes -= 1; if (bytes) { /* shift back high order byte */ val >>= left_shift; /* reset left shift since we did it already */ left_shift = 0; } for (i=1;i > right_shift ); /* reset right shift since we did it already */ right_shift = 0; } return val >> ( left_shift + right_shift ); } /* // bfxi -- bit field extract and increment // // extract up to a 32-bit value at any bit // offset in a byte array and auto-increment // the bit offset by the number of bits read */ inline UINT32 bfxi( const PUCHAR cptr, UINT32 &bit_offset, UINT32 bit_len) { UINT32 val = bfx(cptr, bit_offset, bit_len); bit_offset += bit_len; return val; } #endif
Here’s a small program that uses it:
#include#include "bitfieldextract.h" using namespace std; int main(int argc, char* argv[]) { UCHAR x[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc }; unsigned int ofs = 0; int i; cout << "Binary representation of buffer " << "[ 0x12 0x34 0x56 0x78 0x9a 0xbc ]:" << endl << endl << " "; for (i=0;i<48;i++) cout << bfxi(x, ofs, 1); cout << endl << endl; cout << "Each 4-bit nibble:" << endl << endl << " "; ofs = 0; for (i=0;i<12;i++) printf("0x%1x ", bfxi(x, ofs, 4)); cout << endl << endl; ofs = 2; cout << " 2 bits at " << ofs << " = "; cout << bfxi( x, ofs, 2 ) << endl; cout << " 4 bits at " << ofs << " = "; cout << bfxi( x, ofs, 4 ) << endl; cout << " 6 bits at " << ofs << " = "; cout << bfxi( x, ofs, 6 ) << endl; cout << " 8 bits at " << ofs << " = "; cout << bfxi( x, ofs, 8 ) << endl; cout << "10 bits at " << ofs << " = "; cout << bfxi( x, ofs, 10) << endl; for (i=4;i<=8;i++) { ofs = i; cout << "32 bits at " << ofs << " = "; printf("0x%08x\n", bfxi( x, ofs, 32)); } ofs = 16; cout << "32 bits at " << ofs << " = "; printf("0x%08x\n", bfxi( x, ofs, 32)); return 0; }
And the associated output:
Binary representation of buffer [ 0x12 0x34 0x56 0x78 0x9a 0xbc ]: 000100100011010001010110011110001001101010111100 Each 4-bit nibble: 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 2 bits at 2 = 1 4 bits at 4 = 2 6 bits at 8 = 13 8 bits at 14 = 21 10 bits at 22 = 632 32 bits at 4 = 0x23456789 32 bits at 5 = 0x468acf13 32 bits at 6 = 0x8d159e26 32 bits at 7 = 0x1a2b3c4d 32 bits at 8 = 0x3456789a 32 bits at 16 = 0x56789abc