Method to Unpack byte array into a UInt64

S

stuie_norris

Hi Group

I am trying to write a method to unpack a byte array into an Uint64.
But the results are wrong.

public static void UnpackUint64(ref UInt64 dst, byte[] Data,
ref uint Index)
{
dst = Data[Index++];
dst += (UInt64)((Data[Index++] & 0xffffffff) << 08);
dst += (UInt64)((Data[Index++] & 0xffffffff) << 16);
dst += (UInt64)((Data[Index++] & 0xffffffff) << 24);
dst += (UInt64)((Data[Index++] & 0xffffffff) << 32);
dst += (UInt64)((Data[Index++] & 0xffffffff) << 40);
dst += (UInt64)((Data[Index++] & 0xffffffff) << 48);
dst += (UInt64)((Data[Index++] & 0xffffffff) << 56);
}

The method I use to pack the Uint64 into the byte array is

public static void PackUint64(ulong src, byte[] Data, ref uint
Index)
{
Data[Index++] = (byte)(src & 0xff);
Data[Index++] = (byte)((src >> 08) & 0xff);
Data[Index++] = (byte)((src >> 16) & 0xff);
Data[Index++] = (byte)((src >> 24) & 0xff);
Data[Index++] = (byte)((src >> 32) & 0xff);
Data[Index++] = (byte)((src >> 40) & 0xff);
Data[Index++] = (byte)((src >> 48) & 0xff);
Data[Index++] = (byte)((src >> 56) & 0xff);
}

The Pack looks okay, but I have spent hours on the UnPack and I just
seem to be confusing myself.

Can anyone tell me what is wrong with my unpack method?

Thanks

Stuart
 
J

Jon Skeet [C# MVP]

I am trying to write a method to unpack a byte array into an Uint64.
But the results are wrong.

In what circumstances?
A quick test app works for me, but I've only tried one value.

Can you provide a short but complete program which demonstrates the
problem?
See http://pobox.com/~skeet/csharp/complete.html for what I mean by
that.

Personally, I would use BitConverter (or my own EndianBitConverter,
which allows you to specify endian-ness) to do this.

Matters of style you may wish to note:
1) Use "out" instead of "ref" when you don't care about the input
value
2) Prefer return values to pass-by-ref usually - I would certainly
make Unpack return a ulong instead of taking one by reference
3) Parameter names are conventionally camelCased rather than
PascalCased
4) Your method names use "Uint64" instead of "UInt64" (capitalise the
I)

I guess passing the index by reference allows for some useful use
cases, but it's a bit of a pain in others (where you just want to pass
0, for instance).

Jon
 
S

stuie_norris

Hi Group,

Here is an example that demonstrates the issue with my method. I
would expect the result of the method to display the number after the
PACK and UNPACK.

Pack 2147483648, UnPack 18446744071562067968.

Can anyone tell me what I am doing wrong with my UnPack Method?

Thanks

Stuart

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace UtilityTester
{
class Program
{
public static void PackUint64(ulong src, byte[] Data, ref uint
Index)
{
Data[Index++] = (byte)(src & 0xff);
Data[Index++] = (byte)((src >> 08) & 0xff);
Data[Index++] = (byte)((src >> 16) & 0xff);
Data[Index++] = (byte)((src >> 24) & 0xff);
Data[Index++] = (byte)((src >> 32) & 0xff);
Data[Index++] = (byte)((src >> 40) & 0xff);
Data[Index++] = (byte)((src >> 48) & 0xff);
Data[Index++] = (byte)((src >> 56) & 0xff);
}
public static void UnpackUint64(ref UInt64 dst, byte[] Data,
ref uint Index)
{
dst = Data[Index++];
dst += (UInt64)((Data[Index++] & 0xffff) << 08);
dst += (UInt64)((Data[Index++] & 0xffff) << 16);
dst += (UInt64)((Data[Index++] & 0xffff) << 24);
dst += (UInt64)((Data[Index++] & 0xffff) << 32);
dst += (UInt64)((Data[Index++] & 0xffff) << 40);
dst += (UInt64)((Data[Index++] & 0xffff) << 48);
dst += (UInt64)((Data[Index++] & 0xffff) << 56);
}
static void Main(string[] args)
{
byte[] b = new byte[10];
uint ipack = 0;
uint iunpack = 0;
UInt64 number64 = 0;
UInt64 result64 = 0;

number64 = 2147483648;
ipack = 0;
PackUint64(number64, b, ref ipack);
iunpack = 0;
result64 = 0;
UnpackUint64(ref result64, b, ref iunpack);
Console.WriteLine("Pack {0}, UnPack {1}",
number64,result64);
Thread.Sleep(50000000);
}
}
}
 
J

Jon Skeet [C# MVP]

Here is an example that demonstrates the issue with my method. I
would expect the result of the method to display the number after the
PACK and UNPACK.

Pack 2147483648, UnPack 18446744071562067968.

Can anyone tell me what I am doing wrong with my UnPack Method?

Yup - sorry not to have spotted it before. When you're left-shifting,
you're doing it with an int. Instead, you need to cast to a ulong
first. Here's the corrected method:

public static void UnpackUint64(ref UInt64 dst,
byte[] Data,
ref uint Index)
{
dst = Data[Index++];
dst += ((UInt64)Data[Index++]) << 08;
dst += ((UInt64)Data[Index++]) << 16;
dst += ((UInt64)Data[Index++]) << 24;
dst += ((UInt64)Data[Index++]) << 32;
dst += ((UInt64)Data[Index++]) << 40;
dst += ((UInt64)Data[Index++]) << 48;
dst += ((UInt64)Data[Index++]) << 56;
}

Jon
 
S

stuie_norris

Jon,

Thanks for the reply. That is great. I was just staring at it an not
noticing what is wrong.

Any ideas why I the error

"Cannot implicitily convert type 'int' to 'ushort'. An explicit
conversion exists (are you missing a cast?)"

public static void UnpackUInt16(ref UInt16 dst, byte[] Data,
ref uint Index)
{
dst = (UInt16)Data[Index++];
dst += (UInt16)Data[Index++] << 08; // This line
}

Thanks

Stuart
 
J

Jon Skeet [C# MVP]

Thanks for the reply. That is great. I was just staring at it an not
noticing what is wrong.

Any ideas why I the error

"Cannot implicitily convert type 'int' to 'ushort'. An explicit
conversion exists (are you missing a cast?)"

Yes - only the following left shift operators are predefined:

int operator <<(int x, int count);
uint operator <<(uint x, int count);
long operator <<(long x, int count);
ulong operator <<(ulong x, int count);

So in this case, your ushort is converted to an int, and the result is
an int. You need to cast the result to a ushort.

Note that in this case you don't need the cast on the first line, and
the cast on the second line only needs to be for the whole expression -
the only reason you needed the cast for Data[Index++] in the ulong
situation is because you needed to make it use the last of the operator
overloads listed above rather than the first. So your method can be:

public static void UnpackUInt16(ref UInt16 dst, byte[] Data,
ref uint Index)
{
dst = Data[Index++];
dst += (UInt16)(Data[Index++] << 08);
}
 

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