I know I can extract bytes from int like this:
bytes[] IntToBytes(int i)
{
return new byte [] {(byte) ((i >> 8) & 0xff), (byte) (i & 0xff)};
}
which I subsequently send as part of a serial transmission. But can I do the reverse, after receiving a sequence of bytes, reconstruct the original data, preserving the sign. Currently, I do this, but it feels a bit over the top:
int BytesToInt( byte hi, byte lo)
{
return ((hi << 24) | (lo << 16)) >> 16;
}
Is there another way or a better way? Does it make a difference if I know I am ultimately dealing with signed 16-bit data only?
You're working with signed 16-bit data only. So why are you passing (and returning) an int and not a short? You're throwing the sign information away, so it will not actually work for negative numbers. Instead, use short and you'll be fine - and the extra type information will make your code safer.
byte[] ShortToBytes(short i)
{
return new byte [] {(byte) ((i >> 8) & 0xff), (byte) (i & 0xff)};
}
short BytesToShort(byte hi, byte lo)
{
return unchecked((short)((hi << 8) | lo));
}
The main benefit (apart from being clearer and actually working) is that you can no longer pass an invalid value to the method. That's always good :)
Oh, and I'd recommend keeping the interface symmetric - BytesToShort should also take a byte[] (or some other structure that has the two bytes).
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.
I need to convert an int to a byte array of size 3. This means dropping the last byte, for example:
var temp = BitConverter.GetBytes(myNum).Take(3).ToArray());
However, is there a better way to do is? Maybe by creating a custom struct?
EDIT
For this requirement I have a predefined max value of 16777215 for this new data type.
Something like this (no Linq, just getting bytes)
int value = 123;
byte[] result = new byte[] {
(byte) (value & 0xFF),
(byte) ((value >> 8) & 0xFF),
(byte) ((value >> 16) & 0xFF),
};
Sounds like you want to create a new struct that represents a 3 byte unsigned integer (based solely on the max value quoted).
Using your original method is very prone to failure, firstly, Take(3) is dependent on whether the system you're running on is big-endian or little-endian, secondly, it doesn't take into account what happens when you get passed a negative int which your new struct can't handle.
You will need to write the conversions yourself, I would take in the int as given, check if it's negative, check if it's bigger than 16777215, if it passes those checks then it's between 0 and 16777215 and you can store it in your new struct, simply execute a Where(b => b != 0) instead of Take(3) to get around the endian-ness problem. Obviously take into account the 0 case where all bytes = 0.
I have a problem that I can't solve whole day. I'm new in C# and I'm asking you tog ive me a hand.
I have two ulong values. I need combine their binary representations and get 16 bytes value. I know C# does not support 128 bit types. But I also do not need to hold this value in variable. I need to convert this value to byte array.
I tried to combine values like this:
long a = ((long)b << 64) + (long)c;
and after convert to byte array with BitConverter.
But I realize that this is incorrect, because size of long values is 8 byte.
I don't want to create a 128 type to get result.
So is there a way to combine and add to byte array directly?
Thanks
Microsoft C# supports integers of arbitrary length, using BigInteger. You could combine your two values, such as in the example you have given, like so:
BigInteger a = b;
a <<= 64;
a += c;
However, as you've indiciated you don't need to store this value. Before you mention, yes, I am aware of endianness. There's machine-dependent endianness and over-the-wire endianness. We should not try to produce any machine-dependent endianness... The way we can produce over-the-wire endianness in the languages I'm most familiar with is using the right-shift and modulo operators, at least for unsigned types. Signed types introduce the complication of encoding the sign, but here's an example I think you might benefit from:
byte[] array = { (byte)(b >> 56), (byte)(b >> 48), (byte)(b >> 40), (byte)(b >> 32),
(byte)(b >> 24), (byte)(b >> 16), (byte)(b >> 8), (byte)(b ),
(byte)(c >> 56), (byte)(c >> 48), (byte)(c >> 40), (byte)(c >> 32),
(byte)(c >> 24), (byte)(c >> 16), (byte)(c >> 8), (byte)(c ) };
If I run this:
var x = (ulong)1;
var y = (ulong)2;
var result =
BitConverter.GetBytes(x)
.Concat(BitConverter.GetBytes(y))
.ToArray();
I get this:
Is that what you want?
I guess its homework?
You can represent your terms, the ulongs a and b as byte arrays.
Afterwards you may create a new byte array c for the sum.
For Each byte go bit by bit and just do a normal two's complement binary addition, remember the carry bit from byte to byte.
If the last byte has carry bit then you should throw "ulong addition overflow exception" of some kind.
This is in C#. I was hoping I could do something like the following.
byte byte1 = 100;
byte byte2 = 100;
byte1[1] = byte1[1] ^ byte2[6]; // XOR bit at index 1 against bit at index 6
However, I am currently stuck at:
if ((byte2 ^ (byte)Math.Pow(2, index2)) < byte2)
byte1 = (byte)(byte1 ^ (byte)Math.Pow(2, index1));
Is there a faster way, possibly something similar to what I typed at the top?
Edit:
I had never heard of any of the bitwise operators other than XOR. That's why the original solution had the bizarre Math.Pow() calls. I've already improved my solution considerably according to my benchmarking of millions of loop iterations. I'm sure I'll get it faster with more reading. Thanks to everybody that responded.
byte2 = (byte)(byte2 << (7 - index2));
if (byte2 > 127)
{
byte buffer = (byte)(1 << index1);
byte1 = (byte)(byte1 ^ buffer);
}
Bytes are immutable, you can't change a bit of the byte as if it was an array. You'd need to access the bits through masks (&) and shifts (<< >>), then create a new byte containing the result.
// result bit is the LSB of r
byte r = (byte)((byte1 >> 1 & 1) ^ (byte2 >> 6 & 1));
The specific mask 1 will erase any bit except the right most (LSB).
In the documentation of hardware that allows us to control it via UDP/IP,
I found the following fragment:
In this communication protocol, DWORD is a 4 bytes data, WORD is a 2 bytes data,
BYTE is a single byte data. The storage format is little endian, namely 4 bytes (32bits) data is stored as: d7-d0, d15-d8, d23-d16, d31-d24; double bytes (16bits) data is stored as: d7-d0 , d15-d8.
I am wondering how this translates to C#?
Do I have to convert stuff before sending it over?
For example, if I want to send over a 32 bit integer, or a 4 character string?
C# itself doesn't define the endianness. Whenever you convert to bytes, however, you're making a choice. The BitConverter class has an IsLittleEndian field to tell you how it will behave, but it doesn't give the choice. The same goes for BinaryReader/BinaryWriter.
My MiscUtil library has an EndianBitConverter class which allows you to define the endianness; there are similar equivalents for BinaryReader/Writer. No online usage guide I'm afraid, but they're trivial :)
(EndianBitConverter also has a piece of functionality which isn't present in the normal BitConverter, which is to do conversions in-place in a byte array.)
You can also use
IPAddress.NetworkToHostOrder(...)
For short, int or long.
Re little-endian, the short answer (to do I need to do anything) is "probably not, but it depends on your hardware". You can check with:
bool le = BitConverter.IsLittleEndian;
Depending on what this says, you might want to reverse portions of your buffers. Alternatively, Jon Skeet has specific-endian converters here (look for EndianBitConverter).
Note that itaniums (for example) are big-endian. Most Intels are little-endian.
Re the specific UDP/IP...?
You need to know about network byte order as well as CPU endian-ness.
Typically for TCP/UDP comms, you always convert data to network byte order using the htons function (and ntohs, and their related functions).
Normally network order is big-endian, but in this case (for some reason!) the comms is little endian, so those functions are not very useful. This is important as you cannot assume the UDP comms they have implemented follow any other standards, it also makes life difficult if you have a big-endian architecture as you just can't wrap everything with htons as you should :-(
However, if you're coming from an intel x86 architecture, then you're already little-endian, so just send the data without conversion.
I'm playing around with packed data in UDP Multicast and I needed something to reorder UInt16 octets since I noticed an error in packet header (Wireshark), so I made this:
private UInt16 swapOctetsUInt16(UInt16 toSwap)
{
Int32 tmp = 0;
tmp = toSwap >> 8;
tmp = tmp | ((toSwap & 0xff) << 8);
return (UInt16) tmp;
}
In case of UInt32,
private UInt32 swapOctetsUInt32(UInt32 toSwap)
{
UInt32 tmp = 0;
tmp = toSwap >> 24;
tmp = tmp | ((toSwap & 0xff0000) >> 8);
tmp = tmp | ((toSwap & 0xff00) << 8);
tmp = tmp | ((toSwap & 0xff) << 24);
return tmp;
}
This is just for testing
private void testSwap() {
UInt16 tmp1 = 0x0a0b;
UInt32 tmp2 = 0x0a0b0c0d;
SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1));
SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1)));
Debug.WriteLine("{0}", shb1.ToString());
Debug.WriteLine("{0}", shb2.ToString());
SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2));
SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2)));
Debug.WriteLine("{0}", shb3.ToString());
Debug.WriteLine("{0}", shb4.ToString());
}
from which output was this:
0B0A: {0}
0A0B: {0}
0D0C0B0A: {0}
0A0B0C0D: {0}
If you're parsing and performance is not critical, consider this very simple code:
private static byte[] NetworkToHostOrder (byte[] array, int offset, int length)
{
return array.Skip (offset).Take (length).Reverse ().ToArray ();
}
int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0);