3

Say, i have binary protocol, where first 4 bits represent a numeric value which can be less than or equal to 10 (ten in decimal).

In C++, the smallest data type available to me is char, which is 8 bits long. So, within my application, i can hold the value represented by 4 bits in a char variable. My question is, if i have to pack the char value back into 4 bits for network transmission, how do i pack my char's value back into 4 bits?

Jimm
  • 8,165
  • 16
  • 69
  • 118

4 Answers4

4

You do bitwise operation on the char;

so

  unsigned char packedvalue = 0;

  packedvalue |= 0xF0 & (7 <<4);
  packedvalue |= 0x0F & (10);

Set the 4 upper most bit to 7 and the lower 4 bits to 10

Unpacking these again as

 int upper, lower;

 upper = (packedvalue & 0xF0) >>4;
 lower = packedvalue & 0x0F;

As an extra answer to the question -- you may also want to look at protocol buffers for a way of encoding and decoding data for binary transfers.

Soren
  • 14,402
  • 4
  • 41
  • 67
  • When recovering the values, you need to be careful about signed-ness. – Ben Voigt Jan 16 '12 at 22:55
  • @Ben, The unsigned char should take care of that as long as you pack positive numbers only -- however if you plan to pack a negative number -- (like -2) into a bit field, then you may have to do some more code. – Soren Jan 16 '12 at 22:59
  • why do i need to do 0xF0 & (7<<4), when it yields same result as 7<<4 ? – Jimm Jan 16 '12 at 23:22
  • @Jimm -- It does yield the same result in this specific example -- however I find it more readable as to the intent of what is going on -- readability is always a big concern when making code like this -- the argument have more weight when the actual code of some variable 'abc' is added, where it is not obvious as what the value of 'abc' may be -- then `0xF0 & (abc <<4)` is a better way of writing code. -- second argument for writing `0xF0 &...` ensure safety of your code, so that your variable `abc` is truly truncated to 4 bits in case your calculation overflows or becomes negative – Soren Jan 17 '12 at 00:54
3

Sure, just use one char for your value:

std::ofstream outfile("thefile.bin", std::ios::binary);

unsigned int n;  // at most 10!
char c = n << 4; // fits
outfile.write(&c, 1);  // we wrote the value "10"

The lower 4 bits will be left at zero. If they're also used for something, you'll have to populate c fully before writing it. To read:

infile.read(&c, 1);
unsigned int n = c >> 4;
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • n << 4 will shift n by 4 bits which means it will be using the "more significant" bits. The issue if the number is 8 or 9 is that it will be using the most significant bit. My suggestion thus be to use "unsigned char", particularly for reading back. – CashCow Jan 16 '12 at 23:22
  • The above is writing 8 bits..My question is, how do i write ONLY 4 bits to the output stream in C++ – Jimm Jan 16 '12 at 23:51
  • @Jimm: Naturally you can't since the smallest addressable unit is one `char`. You can however *read* one byte first, manipulate only its upper four bits, and write the result back. – Kerrek SB Jan 17 '12 at 01:10
3

Well, there's the popular but non-portable "Bit Fields". They're standard-compliant, but may create a different packing order on different platforms. So don't use them.

Then, there are the highly portable bit shifting and bitwise AND and OR operators, which you should prefer. Essentially, you work on a larger field (usually 32 bits, for TCP/IP protocols) and extract or replace subsequences of bits. See Martin's link and Soren's answer for those.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

Are you familiar with C's bitfields? You simply write

struct my_bits {
  unsigned v1 : 4;
  ...
};

Be warned, various operations are slower on bitfields because the compiler must unpack them for things like addition. I'd imagine unpacking a bitfield will still be faster than the addition operation itself, even though it requires multiple instructions, but it's still overhead. Bitwise operations should remain quite fast. Equality too.

You must also take care with endianness and threads (see the wikipedia article I linked for details, but the issues are kinda obvious). You should leearn about endianness anyways since you said "binary protocol" (see this previous questions)

Community
  • 1
  • 1
Jeff Burdges
  • 4,204
  • 23
  • 46