0

I am allocating an array that is intentionally bigger than the result of BitConverter.GetBytes. My goal is to leave the last byte empty so that I can prevent this number from being seen as the two's compliment and have tempPosBytes2[

When I run BitConverter.GetBytes my array tempPosBytes2 seems to shrink.

uint positiveNumber = 4293967296;
byte[] tempPosBytes2 = new byte[tempPosBytes.Length + 1]; // four bytes plus one
tempPosBytes2 = BitConverter.GetBytes(positiveNumber);  // tempPositiveBytes2 is now 4 bytes!!

Question

What is going on under the covers, and how can I leave the trailing byte without copying the array?

I need this to work with BigInteger(byte[]) as in the following:

BigInteger positiveBigIntBAD2 = new BigInteger(tempPosBytes2); // Invalid
makerofthings7
  • 60,103
  • 53
  • 215
  • 448

4 Answers4

3

Your array isn't being shrunk, you have an entirely new array allocated inside BitConverter.GetBytes.

Of course you can copy that output data into an array with size of your choice.

Or, just make your own version of BitConverter. It's really simple:

byte[] tempPosBytes2 = new byte[] { (byte)(positiveNumber), 
                                    (byte)(positiveNumber >> 8), 
                                    (byte)(positiveNumber >> 16), 
                                    (byte)(positiveNumber >> 24), 
                                    0 };

I suggest you compare the performance using both techniques.

BTW, you could just use the BigInteger constructor that takes a uint.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
2

It's not shrinking anything. GetBytes allocates a new array, always, and your assignment overwrites the reference to your existing byte array.

If you need the highest byte to always be zero, so that BigInteger doesn't interpret it as a negative number, then you can do Array.Resize after GetBytes to increase the size by 1, and the new byte will have the value zero, like you want.

There's an example on the BigInteger constructor page that talks about this very thing, and it provides an example that will result in only resizing the array when necessary. You could write yourself a helper method CreateUnsignedBigInteger(byte[]) which would do that very thing.

public BigInteger CreateUnsignedBigInteger(byte[] bytes)
{
    if ((bytes[bytes.Length - 1] & 0x80) > 0) 
    {
        byte[] old = bytes;
        bytes = new byte[old.Length + 1];
        Array.Copy(old, bytes, old.Length);
    }

    return new BigInteger(bytes);
}
David Yaw
  • 27,383
  • 4
  • 60
  • 93
  • I thought of a resize, but that is an O(n) operation where n is the size of the array – makerofthings7 Dec 18 '12 at 16:37
  • @makerofthings7: So are all the other operations you're doing on this array. *n* is small. – Ben Voigt Dec 18 '12 at 16:38
  • Yes it's O(n), but `n` is four. We know that it's four, because you're dealing with 32-bit integers. – David Yaw Dec 18 '12 at 16:38
  • This is just an example... my real byte arrays are bigger, and I'm trying to solve a bigger problem. I'm thinking my core issue is the two's compliment. – makerofthings7 Dec 18 '12 at 16:47
  • See edit for a helper method that will resize the array only when necessary, and encapsulates the resize & creation of the BigInteger. – David Yaw Dec 18 '12 at 17:00
  • Here is the expanded version of my question. I was trying this small number example before I started a big number example ... here: http://stackoverflow.com/q/13938483/328397 – makerofthings7 Dec 18 '12 at 18:01
1

BitConverter.GetBytes is not using your array, it cannot because you never passed it in.

Instead what is happening is you are creating an array, and then immediately destroying it.

If you need the result of GetBytes to be in your array, you can see if there is an overload or other method that takes in an array to write to, or copy the content yourself.

Guvante
  • 18,775
  • 1
  • 33
  • 64
1

Ironically enough, if you want a byte[] that you can pass into a BigInteger constructor to give a value equivalent to your uint, you can do

byte[] tempPosBytes = new BigInteger(positiveNumber).ToByteArray();
Rawling
  • 49,248
  • 7
  • 89
  • 127