BitConverter.ToInt16 doesn't work correct

G

Guest

Hello. I have a problem with getting short value from 2 byte array.
I have this code. There are 2 short values in bytes.

byte[] cast = { 18, 152, 00, 80 };
Int32 port = BitConverter.ToInt16(cast, 0); // -26606 - wrong!
Int32 port2 = BitConverter.ToInt16(cast, 2); // 20480 - wrong!

//port and port2 get not correct values
//and I found solution in google
short result1 = (short)(((short)cast[1]) | (short)(cast[0] * 256)); //4760 -
correct!
short result2 = (short)(((short)cast[3]) | (short)(cast[2] * 256)); //80 -
correct!

why it happends? How make BitConverter work correct?
 
P

Peter Duniho

SushiSean said:
Hello. I have a problem with getting short value from 2 byte array.
I have this code. There are 2 short values in bytes.

byte[] cast = { 18, 152, 00, 80 };
Int32 port = BitConverter.ToInt16(cast, 0); // -26606 - wrong!

-26606 is the correct result. Your 16-bit number is 0x9812, which when
interpreted as a signed 16-bit integer is in fact -26606.
Int32 port2 = BitConverter.ToInt16(cast, 2); // 20480 - wrong!

Likewise, 20480 is the correct result. Your 16-bit number is 0x5000,
which when interpreted as a signed 16-bit integer is in fact 20480.
//port and port2 get not correct values

It appears to me that you are confused about the native, little-endian
number format used by the Intel hardware running your code, and the
"network order" used in TCP/IP, which is big-endian.
//and I found solution in google
short result1 = (short)(((short)cast[1]) | (short)(cast[0] * 256)); //4760 -
correct!
short result2 = (short)(((short)cast[3]) | (short)(cast[2] * 256)); //80 -
correct!

Those are only the correct values if your data is in big-endian format.
If your data is in big-endian format, it is a mistake to ask
BitConverter, which operates only on little-endian data, to convert it.
why it happends? How make BitConverter work correct?

Don't lie to it about the data you're passing it. If you want it to
convert data that you have that starts in big-endian format, you need to
convert that data to little-endian before you pass it to BitConverter by
swapping the bytes so that they are in the correct order.

Pete
 
G

Guest

Peter Duniho said:
Don't lie to it about the data you're passing it. If you want it to
convert data that you have that starts in big-endian format, you need to
convert that data to little-endian before you pass it to BitConverter

How to make this convert to little-endian?
 
P

Peter Duniho

SushiSean said:
How to make this convert to little-endian?

It was in my post. You trimmed out the procedure I described in the
above quote.

Beyond that, if you are going to be using BitConverter, you should
probably learn more about actual data formats, and in this case
especially about byte-order and how to deal with differences in that.
And in particular, you seem to be doing network address work here, where
the byte-ordering for the format is very important, since many network
APIs use big-endian even on computers that are natively little-endian.
..NET translates for you, when you give it plain little-endian integers,
but it's quite common to see network addresses stored as big-endian.

Basically, you should probably take a step back and gain better
familiarity with the byte-ordering issue before you attempt to write
code that is dependent on byte-ordering.

Pete
 
M

Michael C

SushiSean said:
Hello. I have a problem with getting short value from 2 byte array.
I have this code. There are 2 short values in bytes.

byte[] cast = { 18, 152, 00, 80 };
Int32 port = BitConverter.ToInt16(cast, 0); // -26606 - wrong!
Int32 port2 = BitConverter.ToInt16(cast, 2); // 20480 - wrong!

//port and port2 get not correct values
//and I found solution in google
short result1 = (short)(((short)cast[1]) | (short)(cast[0] * 256));
//4760 -
correct!
short result2 = (short)(((short)cast[3]) | (short)(cast[2] * 256)); //80 -
correct!

why it happends? How make BitConverter work correct?

You could just do cast[0] * 256 + cast[1]. You will need to work out how to
handle values of 128 or above for the first byte.
 
K

Kevin Spencer

Here is a function I wrote that is designed for a BinaryReader:

byte[] ReadBytes(BinaryReader reader, int length, bool littleEndian)
{
byte[] bytes = new byte[length];
if (littleEndian)
return reader.ReadBytes(length);
else
{
for (int i = length - 1; i > -1; i--)
bytes = reader.ReadByte();
return bytes;
}
}

Simply put, when the byte order is Big-Endian, you reverse the order of the
bytes.

--
HTH,

Kevin Spencer
Microsoft MVP

DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net
 
M

Marc Gravell

Note that this will only work if the binary data is a single value
(however many bytes that is for the type in question); if it is a true
stream of successive values you could be in a pickle.

Minor aside; personally I would have called reader.ReadBytes() to fill
the buffer in either case, and then (if littleEndian) reversed the
buffer locally. Horses for courses...

Marc
 
M

Michael C

Kevin Spencer said:
Here is a function I wrote that is designed for a BinaryReader:

byte[] ReadBytes(BinaryReader reader, int length, bool littleEndian)
{
byte[] bytes = new byte[length];
if (littleEndian)
return reader.ReadBytes(length);
else
{
for (int i = length - 1; i > -1; i--)
bytes = reader.ReadByte();
return bytes;
}
}

Simply put, when the byte order is Big-Endian, you reverse the order of
the bytes.


Doesn't this reverse the order of the entire array?

Michael
 
M

Marc Gravell

from inspection, it appears to - hence my reply; valid in some
circumstances, but by no means all.

For the paranoid: if you are going to start reversing things to
manually compensate for CPU endian-ness (for BitConverter usage), you
might also want to double-check that you need to!
BitConverter.IsLittleEndian will tell you how the CPU works. Itanium
leans the other way... so to speak.

Marc
 
M

Michael C

Marc Gravell said:
from inspection, it appears to - hence my reply; valid in some
circumstances, but by no means all.

For the paranoid: if you are going to start reversing things to manually
compensate for CPU endian-ness (for BitConverter usage), you might also
want to double-check that you need to! BitConverter.IsLittleEndian will
tell you how the CPU works. Itanium leans the other way... so to speak.

Another option would be to convert the bytes back to short and then do
something like

if(BitConverter.IsLittleEndian) //or should that be not?
{
res = ((res & 0xff00) >> 8) || ((res & 0xff) << 8)
}

If res wasn't unsigned then might need to convert first. This might work
too:

res = (res >> 8) || (res << 8)

Michael
 
M

Marc Gravell

That should probably be a bitwise "or" (|), not a logical "or" (||).
And again, it only helps with a few cases (single, simple values like
short). IMO, the better solution is to leave the byte-stream alone,
and use EndianBitConverter. This will work for multiple sequenced
values, and all data types.

Marc
 
K

Kevin Spencer

Hi Michael,

Yes, it does reverse the order of an entire array. I should have mentioned
that this is part of a set of tools for parsing files, the most general of
the tools. I created it for working with GeoTiff images, which can be either
Big-Endian or Little-Endian. Once the Endian-ness of the file is determined,
the class actually sets a global variable, rather than passing a boolean
value to any function. Notice the BinaryReader instance parameter. This is
due to the fact that it is parsing a file.

The actual tool set has multiple methods that employ this method to read the
data in the file a "chunk" at a time. The data type of each "chunk" is
known, and passed to this method as the length parameter. There are
ReadShort, ReadLong, ReadInt32, ReadUInt32, ReadInt16, etc, methods that
employ this method.

I can understand your concern, as it is only the byte order within each
individual "chunk" of data that is reversed, and reading the entire file
into such a method would not work. I hope this clarifies your question.

--
HTH,

Kevin Spencer
Microsoft MVP

DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

Michael C said:
Kevin Spencer said:
Here is a function I wrote that is designed for a BinaryReader:

byte[] ReadBytes(BinaryReader reader, int length, bool littleEndian)
{
byte[] bytes = new byte[length];
if (littleEndian)
return reader.ReadBytes(length);
else
{
for (int i = length - 1; i > -1; i--)
bytes = reader.ReadByte();
return bytes;
}
}

Simply put, when the byte order is Big-Endian, you reverse the order of
the bytes.


Doesn't this reverse the order of the entire array?

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top