Converting to big -endian

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hello All - have a problem that I'm pulling my hair out on. I'm trying to
take a hex value and convert it to 16bit big-endian format. I can eaisly get
it to little-endian format by convert.ToUInt16(&H600) - works like a champ.
But there is no conver to UInt16 big-endian. Am I missing a conversion
function somewhere or do I have to do some shifting and bitmasking to make
this work?
 
Kenny said:
Hello All - have a problem that I'm pulling my hair out on. I'm trying to
take a hex value and convert it to 16bit big-endian format. I can eaisly
get
it to little-endian format by convert.ToUInt16(&H600) - works like a
champ.
But there is no conver to UInt16 big-endian. Am I missing a conversion
function somewhere or do I have to do some shifting and bitmasking to make
this work?

Any routine that converts endianness converts it both ways since it is just
a byte swap so you can use the same method for both.

The "proper" way to do endianness is to have machine specific methods that
either swap or don't depending on the architecture of the machine on which
they are running - In this scenario you don't have to know your architecture
or even think - you just call the method corresponding to the
incoming/outgoing order on all values as they enter and leave your app.

e.g. If my external interface is defined as BigEndian I write

internalVal = BigEndian(externalVal); // incoming
externalVal = BigEndian(internalVal); // outgoing

and if little endian i write:

internalVal = LittleEndian(externalVal); // incoming
externalVal = LittleEndian(internalVal); // outgoing

For any given architecture one of these methods will do nothing and the
other will swap bytes but I don't have to know or care which it is which.

As far as I know no major system does it this way but I came across it as
macros in QNX/Momentics when I was writing embedded C++ and it certainly
makes life much simpler. Of course as macros there is no cost in the no-op
method which is not the case with C#. You could have the same effect by
using something like:

[Conditional("BigEndian")]
void LittleEndian(ref int i) { i = Swap(i); }

[Conditional("LittleEndian")]
void BigEndian(ref int i) { i = Swap(i); }

Of course I appreciate that all the readers of this thread are so embedded
in the MS/intel world that this is a non-issue but personally I keep
forgetting and I like the elegance of this approach.
 
Create a byte array of the same size as the original value. Read the bytes
in the original value into the array in reverse order. Use the BitConverter
class to convert the byte array to the return type. Piece of cake.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer

Presuming that God is "only an idea" -
Ideas exist.
Therefore, God exists.
 
Tried that and it doesnt work... Problem is that bitconvert .ToUInt16
converts back to little-endian. I need to basically mimick the PERL pack
function... If I do this in PERL - $header = pack("n", 0xD0CF); I get d0 cf
if I $header = pack("v", 0xD0CF); I get cf d0 - in .net if I
convert.tou16int(&HD0CF) I get as expected cf d0 - but every different
conversion to big-endian I try I get reults like 35 0 34 0 36 ....
 
There seems to be some misunderstanding going on.

1. BitConverter.ToUInt16 takes a byte array and an index not an int (hex or
otherwise)
2. Convert.ToUint16 only does extension and signed/unsigned conversion.
3. The fact that the input value to any method is hexadecimal constant is
irrelevant.

IPAddress.HostToNetworkOrder(Int16 val) will do the byte swapping for you on
a little endian machine (i.e. intel)
and you an either use (unchecked) casts or the full ugliness of

Convert.ToUInt16( IPAddress.HostToNetworkOrder( Convert.ToInt16(
myUInt ) ) );

It seems to me that the BitConverter methods should be instance methods not
static and there should be an instance for big endian and an instance for
little endian.
 
Nick.. yes you are correct... and thanks for the input.. I kept getting
convert.touint16 confused with bitconverter.touint16.. sublte distinction
that can get overlooked.. I actually took Kevin's advice and put into an
array an looped backwards then use the bitocnverter with the proper index.
This whole process is so annoying all for a customer who wants a data file
with one particular column in big-endian order.. why I have no idea... any
way here is what I did to make it work. .any suggestions for makign better?

Dim foo As Byte() = BitConverter.GetBytes(&H1AE1)
Dim bar() As Byte = New Byte((foo.Length - 1)) {}

Dim i As Integer = 0
Dim u As Integer = 0
For i = foo.Length - 1 To 0 Step -1
bar(u) = foo(i)
u += 1
Next

BitConverter.ToUInt16(bar, 2)

this will mimick perl... pack("n",0x1AE1)

Kevin Spencer.. r u the same Kevin Spencer from takempis.com? If so remember
me I was one of your MVP a long time ago.. how have you been?
 
You lost me, Kenny. I have been using the function I described for quite
awhile without issues. The only difference is that I am reading from a
stream. But I'm reversing the bytes and using a BitConverter to convert them
back. Here's the acutal code I wrote:

/// <summary acc="protected" type="System.UInt16">
/// Overloaded.Reads a <c>System.UInt16</c> value using Big-Endian
/// or Little-Endian byte order.
/// </summary>
/// <param name="reader"><c>System.IO.BinaryReader</c> to read from.</param>
/// <returns><c>System.UInt16</c> value.</returns>
/// <remarks>Reads from the current position of the <paramref
name="reader"/>.</remarks>
protected ushort ReadUInt16(BinaryReader reader)
{
if (_ByteOrder == ByteOrder.LittleEndian)
{
return reader.ReadUInt16();
}
else // Big-Endian
{
byte[] bytes = new byte[2];
bytes[1] = reader.ReadByte();
bytes[0] = reader.ReadByte();
return BitConverter.ToUInt16(bytes, 0);
}
}

/// <summary acc="protected" type="System.UInt16">
/// Overloaded.Reads a <c>System.UInt16</c> value using Big-Endian
/// or Little-Endian byte order.
/// </summary>
/// <param name="reader"><c>System.IO.BinaryReader</c> to read from.</param>
/// <param name="Offset">Offset from beginning of file.</param>
/// <returns><c>System.UInt16</c> value.</returns>
protected ushort ReadUInt16(BinaryReader reader, long Offset)
{
reader.BaseStream.Seek(Offset, SeekOrigin.Begin);
return ReadUInt16(reader);
}

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer

Presuming that God is "only an idea" -
Ideas exist.
Therefore, God exists.
 
Hi Kenny,

Your code looks pretty good.

Yes, I'm the same guy, but it's been a long time, so I can't say
specifically that I remember you. Still, it's good to hear from you again!

--

Kevin Spencer
Microsoft MVP
..Net Developer

Presuming that God is "only an idea" -
Ideas exist.
Therefore, God exists.
 
But this is much slower than bit shuffling with HostToNetworkOrder or just
doing it yourself.

Why would you bother splitting it into a byte array first?

Even if it is already in a byte array it is simpler code to just convert it
and then use HostToNetworkOrder to shufle the bits.
 
Hi Nick,
But this is much slower than bit shuffling with HostToNetworkOrder or just
doing it yourself.

I suppose it all depends on what you're doing. If you're working with a
UInt16 in the first place, maybe. I'm not entirely sure that using
HostToNetworkOrder is more efficient otherwise. It may simply be doing what
you're talking about. After all, the bytes *do* have to be reversed. So, in
your case, you're adding the step of converting the bytes to a UInt16 and
then calling a function which converts the UInt16 to an array of bytes,
reverses the order, and then converts the array of bytes back to a number. I
suppose it is possible that it does it all in an unmanaged bitwise way under
the hood, but I doubt it.

In addition, this is fine and dandy if the data you're working with is
confined to 16, 32, or 64-bit numbers. Otherwise, you will have to roll your
own method, as I've done in my library, which works with a large variety of
data types, for the purpose of reading TIFF files.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer

Presuming that God is "only an idea" -
Ideas exist.
Therefore, God exists.
 
Back
Top