10

I have a byte array which contains double values. I want to convert It to double array. Is it possible in C#?

Byte array looks like:

byte[] bytes; //I receive It from socket

double[] doubles;//I want to extract values to here

I created a byte-array in this way (C++):

double *d; //Array of doubles
byte * b = (byte *) d; //Array of bytes which i send over socket
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
Tadeusz
  • 6,453
  • 9
  • 40
  • 58

2 Answers2

15

You can't convert an array type; however:

byte[] bytes = ...
double[] values = new double[bytes.Length / 8];
for(int i = 0 ; i < values.Length ; i++)
    values[i] = BitConverter.ToDouble(bytes, i * 8);

or (alterntive):

byte[] bytes = ...
double[] values = new double[bytes.Length / 8];
Buffer.BlockCopy(bytes, 0, values, 0, values.Length * 8);

should do. You could also do it in unsafe code:

byte[] bytes = ...
double[] values = new double[bytes.Length / 8];
unsafe
{
    fixed(byte* tmp = bytes)
    fixed(double* dest = values)
    {
        double* source = (double*) tmp;
        for (int i = 0; i < values.Length; i++)
            dest[i] = source[i];
    }
}

not sure I recommend that, though

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 2
    What if the data is big-endian? – Gabe Oct 20 '11 at 06:59
  • @Marc Garvell i read a text file via File.ReadAllBytes() API and then using for loop i just did doubleArray[i] = byteArray[i]; After the loop ends, both the contents of array were same. Yes the size of array was 1000 items. So when exactly should one use BitConverter? If above solution works. – Zenwalker Oct 20 '11 at 07:00
  • @Gabe indeed; then they'll need to handle that ;p – Marc Gravell Oct 20 '11 at 07:03
  • @zenwalker I'm assuming the data is an IEEE-754 encoded double, so there are 1/8th the doubles are there are bytes. `doubleArray[i] = byteArray[i];` does something rather simpler, and will end up with a lot of doubles holding integer values in the range [0-255] – Marc Gravell Oct 20 '11 at 07:05
  • @MarcGravell true w.r.t range of a byte, but where else do you see its getting exceeded? Always bytes are 255 limited right? – Zenwalker Oct 20 '11 at 07:09
  • @zenwalker I don't understand the question, or what you are trying to describe. Yes c# bytes are unsigned, so [0-255]; but assigning a byte to a double is unlikely to be the right interpretation of data considering it was stored with c++ direct cast. – Marc Gravell Oct 20 '11 at 07:11
  • @Gabe Then claerly Jon Skeet has a library to do it :-) http://www.yoda.arachsys.com/csharp/miscutil/ look under `MiscUtil.Conversion.EndianBitConverter` – xanatos Oct 20 '11 at 07:15
  • Just out of idle curiosity, is there some mysterious reason for the not using `bytes.Length` as the last parameter of BlockCopy? – Benjol Sep 13 '12 at 08:33
  • @Benjol yes; if the original array is incorrectly sized, i.e. it has 20 bytes (2 doubles and a bit), then the new double-array is only length 2. We want to copy 16 bytes, not 20. Copying 20 would case an exception. – Marc Gravell Sep 13 '12 at 11:17
  • @MarcGravell, yikes, I've still got a long way to go in defensive programming! – Benjol Sep 14 '12 at 05:17
9

I'll add a reference to the super-unsafe code from here C# unsafe value type array to byte array conversions

Be aware that it's based on an undocumented "feature" of C#, so tomorrow it could die.

[StructLayout(LayoutKind.Explicit)]
struct UnionArray
{
    [FieldOffset(0)]
    public byte[] Bytes;

    [FieldOffset(0)]
    public double[] Doubles;
}

static void Main(string[] args)
{
    // From bytes to floats - works
    byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64 };
    UnionArray arry = new UnionArray { Bytes = bytes };

    for (int i = 0; i < arry.Bytes.Length / 8; i++)
        Console.WriteLine(arry.Doubles[i]);   
}

The only advantage of this method is that it doesn't really "copy" the array, so it's O(1) in space and time over other methods that copy the array that are O(n).

Community
  • 1
  • 1
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • @MarcGravell Intriguing... Does it uses memory pages sharing? Otherwise it can't be less than O(n) – xanatos Oct 20 '11 at 07:10
  • MSDN states "As its name suggests, the BlockCopy method copies a block of bytes as a whole, rather than copying one byte at a time. " - however, it is implemented as an `extern`, so I can't tell you what the underlying implementation is. I would *imagine* that it calls down to something like `memcpy`. – Marc Gravell Oct 20 '11 at 07:14
  • @MarcGravell Then the whole operation is O(n) in space and time (in time because to copy n bytes you have to copy all the n bytes and so you'll have to do n/k operations, where is a constant and is the number of bytes you copy at a time (4 or 8), and in space because you need to allocate a second array of size n bytes). Clearly it's faster than copying them "manually". I had hoped it used one of those "dirty tricks" of copy-on-write :-) – xanatos Oct 20 '11 at 07:16