I have 2 bytes that should populate this way:
first number (4b) second number (12b)
So 4 bit can be between 1-15
And 12 bit can be between 1-50
So i have this Bytes Array:
byte[] packetArrayBytes = new byte[Length];
The way I've understood the question is that you've got these two (presumably) unsigned integers a and b:
(I'll be writing them in hexadecimal to make it easier to read)
a: 0x0000000X
b: 0x00000XXX
Where a is the 4-bit number and b is the 12-bit one, with the Xs marking the bits containing the relevant values.
You want to store them in two separate 8-bit chunks: c: 0x00 and d: 0x00
So you need to shift the bits into position, like this:
byte[] packetArrayBytes = new byte[2];
uint intA = 0xF; // Allowed range is 0-15 (0x0-0xF)
uint intB = 0xABC; // Allowed range is 0-4095 (0x0-0xFFF)
// Need to convert from uint to bytes:
byte[] bytesA = BitConverter.GetBytes(intA);
byte[] bytesB = BitConverter.GetBytes(intB);
byte a = bytesA[0]; // a is 0x0F
byte b = bytesB[1]; // b is 0x0A
int c = 0x00; // c is 0x00
int d = bytesB[0]; // d is 0xBC
// Mask out 4 least significant bits of a,
// then shift 4 bits left to place them in the most significant bits (of the byte),
// then OR them into c.
c |= (a & 0x0F) << 4; // c is now 0xF0
// Mask out 4 least significant bits of b,
// then OR them into c.
c |= b & 0x0F; // c is now 0xFA
packetArrayBytes[0] = (Byte)c;
packetArrayBytes[1] = (Byte)d;
Console.WriteLine(BitConverter.ToString(packetArrayBytes)); // Prints "FA-BC"
After doing these operations, the values of a and b should be placed in the bytes c and d like this:
c: 0xFA d: 0xBC. Which you can then place into your array.
To get the values back you just do these same operations in reverse.
If a and b are signed values, I believe the same operations work, but you'll have to make sure you're not interpreting them as unsigned when reading the data back into numbers.
Related
Okay so this may sound ridiculous, but as a personal project, I am trying to re-create a TCP networking protocol in C#.
Every TCP packet received has a header that must start with with two Int4 (0 - 15) forming a single Byte. I think using bitwise operators I have extracted the two Int4 from the byte:
Byte firstInt4 = headerByte << 4;
Byte secondInt4 = headerByte >> 4;
The issue is that I now need to be able to write two Int4 to a single Byte, but I have no idea how to do this.
Yes, bitwise operations will do:
Split:
byte header = ...
byte firstInt4 = (byte) (header & 0xF); // 4 low bits
byte secondInt4 = (byte) (headerByte >> 4); // 4 high bits
Combine:
byte header = (byte) ((secondInt4 << 4) | firstInt4);
An int4 is called a "nibble": half a byte is a nibble. :)
Something like:
combinedByte = hiNibble;
combinedByte << 4; // Make space for second nibble.
combinedByte += loNibble;
should do what you want.
Lets say I have the following four variables: player1X, player1Y, player2X, player2Y. These have, for example, respectively the following values: 5, 10, 20, 12. Each of these values is 8 bits at max and I want to store them into one integer (32 bits), how can I achieve this?
By doing this, I want to create a dictionary, keeping count of how often certain states have happened in the game. For example, 5, 10, 20, 12 is one state, 6, 10, 20, 12 would be another.
You can use BitConverter
To get one Integer out of 4 bytes:
int i = BitConverter.ToInt32(new byte[] { player1X, player1Y, player2X, player2Y }, 0);
To get the four bytes out of the integer:
byte[] fourBytes = BitConverter.GetBytes(i);
To "squeeze" 4 8 bits value in a 32 bit space, you need to "shift" the bits for your various values, and add them together.
The opposite operations is to "unshift" and use some modulo to get the individual numbers you need.
Here is an alterantive:
Make a struct with defined packing. Expose:
The int32 and all 4 bytes at the same time
Make sure the apcking overlaps (i.e. int starts at 0, byte variables at 0, 1,2,3
Done.
And you can easily access and work with them WITHOUT a bitconverter et al and never have to define an array, which is expensive jsut to throw it away.
You can place the values by shifting to the apropriate offset
Example:
// Composing
byte x1 = ...;
byte x2 = ...;
byte x3 = ...;
byte x4 = ...;
uint x = x1 | (x2 << 0x8) | (x3 << 0x10) | (x4 << 0x18);
// Decomposing
uint x = ...;
byte x1 = x & 0xFF;
byte x2 = (x >> 0x8) & 0xFF;
byte x3 = (x >> 0x10) & 0xFF;
byte x4 = (x >> 0x18) & 0xFF;
Alright so here goes.
I currently need to write an extension method for the System.IO.BinaryReader class that is capable of reading a specific format.
I have no idea what this format is called but I do know exactly how it works so i will describe it below.
Each byte that makes up the value is flagged to indicate how the reader will need to behave next.
The first byte has 2 flags, and any subsequent bytes for the value have only 1 flag.
First byte:
01000111
^^^^^^^^
|||____|_ 6 bit value
||_______ flag: next byte required
|________ flag: signed value
Next bytes:
00000011
^^^^^^^^
||_____|_ 7 bit value
|________ flag: next byte required
The first byte in the value has 2 flags, the first bit is if the value is positive or negative.
The second bit is if another byte needs to be read.
The 6 remaining bits is the value so far which will need to be kept for later.
If no more bytes need to be read then you just return the 6 bit value with the right sign as dictated by the first bit flag.
If another byte needs to be read then you read the first bit of that byte, and that will indicate if another byte needs to be read.
The remaining 7 bits are the value here.
That value will need to be joined with the 6 bit value from the first byte.
So in the case of the example above:
The first value was this: 01000111.
Which means it is positive, another byte needs to be read, and the value so far is 000111.
Another byte is read and it is this: 00000011
Therefore no new bytes need to be read and value here is this: 0000011
That is joined onto the front of the value so far like so: 0000011000111
That is therefore the final value: 0000011000111 or 199
0100011100000011 turns into this: 0000011000111
Here is another example:
011001111000110100000001
^^^^^^^^^^^^^^^^^^^^^^^^
| || ||______|_____ Third Byte (1 flag)
| ||______|_____________ Second Byte (1 flag)
|______|_____________________ First Byte (2 flags)
First Byte:
0 - Positive
1 - Next Needed
100111 - Value
Second Byte:
1 - Next Needed
0001101 - Value
Third Byte:
0 - Next Not Needed
0000001 - Value
Value:
00000010001101100111 = 9063
Hopefully my explanation was clear :)
Now i need to be able to write a clear, simple and, and most importantly fast extension method for System.IO.BinaryReader to read such a value from a stream.
My attempts so far are kind of bad and unnecessarily complicated involving boolean arrays and bitarrays.
Therefore I could really do with somebody helping me out with this in writing such a method, that would be really appreciated!
Thanks for reading.
Based on the description in the comments I came up with this, unusually reading in signed bytes since it makes the continue flag slightly easier to check: (not tested)
static int ReadVLQInt32(this BinaryReader r)
{
sbyte b0 = r.ReadSByte();
// the first byte has 6 bits of the raw value
int shift = 6;
int raw = b0 & 0x3F;
// first continue flag is the second bit from the top, shift it into the sign
sbyte cont = (sbyte)(b0 << 1);
while (cont < 0)
{
sbyte b = r.ReadSByte();
// these bytes have 7 bits of the raw value
raw |= (b & 0x7F) << shift;
shift += 7;
// continue flag is already in the sign
cont = b;
}
return b0 < 0 ? -raw : raw;
}
It can easily be extended to read a long too, just make sure to use b & 0x7FL otherwise that value is shifted as an int and bits would get dropped.
Version that checks for illegal values (an overlong sequence of 0xFF, 0xFF... for example, plus works with checked math of C# (there is an option in the C# compiler to use cheched math to check for overflows)
public static int ReadVlqInt32(this BinaryReader r)
{
byte b = r.ReadByte();
// the first byte has 6 bits of the raw value
uint raw = (uint)(b & 0x3F);
bool negative = (b & 0x80) != 0;
// first continue flag is the second bit from the top, shift it into the sign
bool cont = (b & 0x40) != 0;
if (cont)
{
int shift = 6;
while (true)
{
b = r.ReadByte();
cont = (b & 0x80) != 0;
b &= 0x7F;
if (shift == 27)
{
if (negative)
{
// minumum value abs(int.MinValue)
if (b > 0x10 || (b == 0x10 && raw != 0))
{
throw new Exception();
}
}
else
{
// maximum value int.MaxValue
if (b > 0xF)
{
throw new Exception();
}
}
}
// these bytes have 7 bits of the raw value
raw |= ((uint)b) << shift;
if (!cont)
{
break;
}
if (shift == 27)
{
throw new Exception();
}
shift += 7;
}
}
// We use unchecked here to handle int.MinValue
return negative ? unchecked(-(int)raw) : (int)raw;
}
I plan to send raw binary data from a GSM module to a Web API controller. I'm simulating sending the data with Fiddler. The data format is 8 bytes eg.
0x18 0x01 0x1B 0x02 0x12 0x10 0x2D 0x0A
I receive the data at the controller in a 16 byte array:
the data looks correct:
byte 0 = 49 (Ascii char 1) (binary 0011 0001)
byte 1 = 56 (Ascii char 8) (binary 0011 1000)
I need to combine both these bytes to create a single byte of 0x18 (binary 0001 1000)
Looking at the binary values, it looks like i need to shift byte 0 left 4 places, then use the and operator with byte 1?
I'm a bit stuck if anyone could please help.
Thank you
Using bit operators:
byte a = 49;
byte b = 56;
a <<= 4;
b <<= 4;
b >>= 4;
byte result = (byte)(b + a);
Console.WriteLine("{0}", result);
Basically Explicit type casting means there is Possible loss of precision
example :
short s = 256;
byte b = (byte) s;
Console.WriteLine(b);
// output : 0
or
short s = 257;
byte b = (byte) s;
Console.WriteLine(b);
// output : 1
or
short s = 1024;
byte b = (byte)s;
Console.WriteLine(b);
Console.ReadKey();
// output : 0
Base behind this output ... ?
Short is a 2-byte number, byte is 1-byte!
When you cast from two bytes to one you are losing the first
8 bits: 1024 (short: "0000 0100" "0000 0000").
Which in binary becomes (binary: "0000 0000") = 0.
The base behind your output is simple:
Every number is represented as bits, every 8 bits create 1 byte.
Byte holds numbers from "0" to "255".
If you convert bigger number to smaller in programing you are losing bits not just precision.
In your case you are losing every bit after the 8 (If the number you are trying to convert has value holed in its last 8 bits (bit can be 1 or 0) you will get it if not you will get 0).
P.S. Use windows calculator in programmer mode or find a program in google to convert number to bits and it will become more clear to you.