Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Copy variables into buffer without creating garbage?

Tags:

c#

.net

buffer

Is it possible in C# .Net (3.5 and above) to copy a variable into a byte[] buffer without creating any garbage in the process?

For instance:

int variableToCopy = 9861;

byte[] buffer = new byte[1024];
byte[] bytes = BitConverter.GetBytes(variableToCopy);
Buffer.BlockCopy(bytes, 0, buffer, 0, 4);

float anotherVariableToCopy = 6743897.6377f;
bytes = BitConverter.GetBytes(anotherVariableToCopy);
Buffer.BlockCopy(bytes, 0, buffer, 4, sizeof(float));

...

creates the byte[] bytes intermediary object which becomes garbage (presuming a ref is no longer held to it)...

I wonder if using bitwise operators the variable can be copied directly into the buffer without creating the intermediary byte[]?

like image 237
markmnl Avatar asked Mar 09 '13 05:03

markmnl


2 Answers

Use pointers is the best and the fastest way: You can do this with any number of variables, there is no wasted memory, the fixed statement has a little overhead but it's too small

        int v1 = 123;
        float v2 = 253F;
        byte[] buffer = new byte[1024];
        fixed (byte* pbuffer = buffer)
        {
            //v1 is stored on the first 4 bytes of the buffer:
            byte* scan = pbuffer;
            *(int*)(scan) = v1;
            scan += 4; //4 bytes per int

            //v2 is stored on the second 4 bytes of the buffer:
            *(float*)(scan) = v2;
            scan += 4; //4 bytes per float
        }
like image 109
Rafael Avatar answered Sep 20 '22 21:09

Rafael


Why can't you just do:

byte[] buffer = BitConverter.GetBytes(variableToCopy);

Note that the array here is not an indirection into the storage for the original Int32, it is very much a copy.

You are perhaps worried that bytes in your example is equivalent to:

unsafe
{
    byte* bytes = (byte*) &variableToCopy;
}

.. but I assure you that it is not; it is a byte by byte copy of the bytes in the source Int32.

EDIT:

Based on your edit, I think you want something like this (requires unsafe context):

public unsafe static void CopyBytes(int value, byte[] destination, int offset)
{
    if (destination == null)
        throw new ArgumentNullException("destination");

    if (offset < 0 || (offset + sizeof(int) > destination.Length))
        throw new ArgumentOutOfRangeException("offset");

    fixed (byte* ptrToStart = destination)
    {
        *(int*)(ptrToStart + offset) = value;
    }
}
like image 25
Ani Avatar answered Sep 21 '22 21:09

Ani