2

What's the best way to convert a fixed byte or char[100] to a managed char[] in C#? I ended up having to use pointer arithmetic and I'm wondering if there is an easier way -- something like a memcpy or another way?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace StructTest
{

    [StructLayout(LayoutKind.Explicit)]
    unsafe struct OuterType
    {
        private const int BUFFER_SIZE = 100;

        [FieldOffset(0)]
        private int transactionType;

        [FieldOffset(0)]
        private fixed byte writeBuffer[BUFFER_SIZE];

        public int TransactionType
        {
            get { return transactionType; }
            set { transactionType = value; }
        }

        public char[] WriteBuffer
        {
            set
            {
                char[] newBuffer = value;

                fixed (byte* b = writeBuffer)
                {
                    byte* bptr = b;
                    for (int i = 0; i < newBuffer.Length; i++)
                    {
                         *bptr++ = (byte) newBuffer[i];
                    }
                }
            }

            get
            {
                char[] newBuffer = new char[BUFFER_SIZE];

                fixed (byte* b = writeBuffer)
                {
                    byte* bptr = b;
                    for (int i = 0; i < newBuffer.Length; i++)
                    {
                        newBuffer[i] = (char) *bptr++;
                    }
                }

                return newBuffer;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OuterType t = new OuterType();
            t.WriteBuffer = "hello there".ToCharArray();
            System.Console.WriteLine(t.WriteBuffer);
        }
    }
}
Taylor Leese
  • 51,004
  • 28
  • 112
  • 141

2 Answers2

3

You can use Marshal.Copy for that. Notice it is also overloaded for byte[], which might be a more appropriate data type.

Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
  • I updated the WriteBuffer property to return a byte[] and then used Marshal.Copy. It probably should have been byte[] in the first place. – Taylor Leese Jul 27 '09 at 02:46
0

I don't know of a better way to do the conversion on a fixed variable. However one way to make this simpler is to avoid the use of a fixed variable altogether. Instead use a normal C# array and mark it as a UnmanagedType.ByValArray

[FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = BUFFER_SIZE)]
private byte[] writeBuffer;

Then you can use a simple LINQ query to translate the data. Full solution below

[StructLayout(LayoutKind.Explicit)]
unsafe struct OuterType
{
    private const int BUFFER_SIZE = 100;

    [FieldOffset(0)]
    private int transactionType;

    [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = BUFFER_SIZE)]
    private byte[] writeBuffer;

    public int TransactionType
    {
        get { return transactionType; }
        set { transactionType = value; }
    }

    public char[] WriteBuffer
    {
        set { writeBuffer = value.Cast<byte>().ToArray(); }
        get { return writeBuffer.Cast<char>().ToArray(); }
    }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    I had tried an UnmanagedType.ByValArray on writeBuffer but I was getting runtime exceptions like below. Wouldn't that exception also occur for your example? If not, could you enlighten me why? Unhandled Exception: System.TypeLoadException: Could not load type 'StructTest.OuterType' from assembly 'StructTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field. at StructTest.Program.Main(String[] args) – Taylor Leese Jul 26 '09 at 19:20
  • The limitation that I have is that I need my struct to be a union which is why I need FieldOffset(0) for each. – Taylor Leese Jul 26 '09 at 19:24
  • I tried this and I am getting the exception I commented on earlier if they both have FieldOffset(0). – Taylor Leese Jul 27 '09 at 01:02
  • Yeah, that probably doesn't work because .NET doesn't allow a union with reference types. – N8allan Oct 31 '12 at 18:18