4

I have this method to convert long to little endian byte array

public static byte[] UnsignedIntegerToLEByteArray(ulong value)
{    
    // Value in bytes... in your system's endianness (let's say: little endian)
    byte[] bytes = BitConverter.GetBytes(value);

    // If it was big endian, reverse it
    if (!BitConverter.IsLittleEndian)
        Array.Reverse(bytes); 

    return bytes;
}

My goal is to use it for shorted data types too, like int, short, etc. See here:

byte a = 0xAA;
ushort b = 0xEEAA;
uint c = 0xAABBCCDD;
ulong d = 0xAABBCCDDAAAAAABB;
// If you passed short below, you are only interested
// in first two bytes of the array
byte []tmp = DppUtilities.UnsignedIntegerToLEByteArray(b);

This works if my machine is little endian. Will it also work if it is run on big endian machine? I think yes, but I would like to verify.

0

3 Answers 3

3

You can play a trick with a help of IntPtr and Marshal in order to convert any struct (including byte, ushort and ulong):

// Disclaimer: the structure will be reversed as a whole, not field by field
public static byte[] ToLEByteArray<T>(T value) where T: struct {
  int size = Marshal.SizeOf(typeof(T));
  byte[] bytes = new byte[size];

  IntPtr p = Marshal.AllocHGlobal(size);

  try {
    Marshal.StructureToPtr(value, p, true);
    Marshal.Copy(p, bytes, 0, size);
  }
  finally {
    Marshal.FreeHGlobal(p);
  }

  // If it was big endian, reverse it
  if (!BitConverter.IsLittleEndian)
    Array.Reverse(bytes);

  return bytes;
}

....

  Byte b = 123;
  ushort s = 123;
  ulong l = 123;

  Byte[] result_byte = ToLEByteArray(b);
  Byte[] result_ushort = ToLEByteArray(s);
  Byte[] result_ulong = ToLEByteArray(l);

....

  int i = 123456; 
  Byte[] result_int = ToLEByteArray(i);

EDIT: what's wrong with the implementation in the question? (from the comment). Or, restating the question, what is that stuff with IntPtr, Marshal for?

The main issue of the question's implementation is the initial conversion to ulong:

  // all the arguments will be converted to ulong 
  public static byte[] UnsignedIntegerToLEByteArray(ulong value)

In order to illustrate the problem, imagine, that we have two values

Byte  x = 0x12;               // 18
ulong u = 0x0000000000000012; // 18

and the expected output is

new byte[] {0x12};                      // for a single byte
new byte[] {0x12, 0, 0, 0, 0, 0, 0, 0}; // for 8 bytes, i.e. ulong 

however, the actual output will be

new byte[] {0x12, 0, 0, 0, 0, 0, 0, 0};

for both byte and ulong. This misbehaviour can lead to problems if you, say, want to write down numeric values (byte, short, ulong etc.), to a binary file, pass them to a binary stream etc:

  using (Stream stm = ...) {
    ...
    Byte[] buffer = UnsignedIntegerToLEByteArray(...);

    stm.Write(buffer, offset, buffer.Length); // <- the (possibly!) erroneous write
    ...
  }
Sign up to request clarification or add additional context in comments.

8 Comments

If you have some struct with multiple fields, is not you have to reverse each individual field instead of struct as whole?
@PetSerAl: it reverses the struct as whole; so the implmentation is not very useful for arbitrary struct
@quser: in your current implmentation (that's in the question) you cast to ulong so if actual argument, say, is Byte it'll be treated as ulong and you'll get 8 items array instead of 1 item one
Yeah but that is no issue for me, then I will read only the first byte back of the array (I know I passed a byte to it in the first place, right?). Some other issues?
@quser: technically, you can take the first item of the array for byte, or, say, first 4 items for uint but it's an error prone implementation: you have to do a post-call procedure for each call of the method.
|
0

I had the same thing and I tested it.

I can tell you it works 100%. If you want to check it out yourself, you can for example just pretend you need it the other way. So you reverse the byte array and reverse it if it's IsLittleEndian.

Your output is always in LittleEndian in your method, which is what you want.

Comments

0

Like BitConverter.GetBytes has different overloads for that, you should do it the same way:

public static byte[] UnsignedIntegerToLEByteArray(ulong value) { ...
public static byte[] UnsignedIntegerToLEByteArray(int value) { ...
public static byte[] UnsignedIntegerToLEByteArray(short value) { ...

The complier chooses the right overload when using it like you already did:

byte []tmp = DppUtilities.UnsignedIntegerToLEByteArray(b);

If you try to do this with a single method that try to check the zero bytes, it will produce wrong results: How to tell if the number 00 00 12 34 should reverse 2 or 4 bytes?

9 Comments

"If you try to do this with a single method that try to check the zero bytes, it will produce wrong results: How to tell if the number 00 00 12 34 should reverse 2 or 4 bytes?" Can you please explain what you mean here? I tested my function with many possibilities and it works
If I understood you correctly, you have a single method, and you pass all different types (int, short, ...) to the method using a implicit cast. How will the method know how many bytes it has to reverse?
It will cast uint to ulong reverse long and give me back array, please try
What if you pass a low value, say 1, to the method?
So what it will interpret 1 as long, get array of bytes from it in little endian way, and return me result. Isn't it?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.