title: C# performance - Using unsafe pointers instead of IntPtr and Marshal
body: <h1>Question</h1>
  
  <p>I'm porting a C application into C#. The C app calls lots of functions from a 3rd-party DLL, so I wrote P/Invoke wrappers for these functions in C#. Some of these C functions allocate data which I have to use in the C# app, so I used <code>IntPtr</code>'s, <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.ptrtostructure.aspx" rel="noreferrer"><code>Marshal.PtrToStructure</code></a> and <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.copy.aspx" rel="noreferrer"><code>Marshal.Copy</code></a> to copy the native data (arrays and structures) into managed variables. </p>
  
  <p>Unfortunately, the C# app proved to be much slower than the C version. A quick performance analysis showed that the above mentioned marshaling-based data copying is the bottleneck. <strong>I'm considering to speed up the C# code by rewriting it to use pointers instead.</strong> Since I don't have experience with unsafe code and pointers in C#, I need expert opinion regarding the following <strong>questions</strong>:</p>
  
  <ol>
  <li>What are the drawbacks of using <code>unsafe</code> code and pointers instead of <code>IntPtr</code> and <code>Marshal</code>ing? For example, is it more unsafe (pun intended) in any way? People seem to prefer marshaling, but I don't know why.</li>
  <li>Is using pointers for P/Invoking really faster than using marshaling? How much speedup can be expected approximately? I couldn't find any benchmark tests for this.</li>
  </ol>
  
  <h1>Example code</h1>
  
  <p>To make the situation more clear, I hacked together a small example code (the real code is much more complex). I hope this example shows what I mean when I'm talking about "unsafe code and pointers" vs. "IntPtr and Marshal".</p>
  
  <h2>C library (DLL)</h2>
  
  <p>MyLib.h</p>
  
  <pre><code>#ifndef _MY_LIB_H_
  #define _MY_LIB_H_
  
  struct MyData 
  {
    int length;
    unsigned char* bytes;
  };
  
  __declspec(dllexport) void CreateMyData(struct MyData** myData, int length);
  __declspec(dllexport) void DestroyMyData(struct MyData* myData);
  
  #endif // _MY_LIB_H_
  </code></pre>
  
  <p>MyLib.c</p>
  
  <pre><code>#include &lt;stdlib.h&gt;
  #include "MyLib.h"
  
  void CreateMyData(struct MyData** myData, int length)
  {
    int i;
  
    *myData = (struct MyData*)malloc(sizeof(struct MyData));
    if (*myData != NULL)
    {
      (*myData)-&gt;length = length;
      (*myData)-&gt;bytes = (unsigned char*)malloc(length * sizeof(char));
      if ((*myData)-&gt;bytes != NULL)
        for (i = 0; i &lt; length; ++i)
          (*myData)-&gt;bytes[i] = (unsigned char)(i % 256);
    }
  }
  
  void DestroyMyData(struct MyData* myData)
  {
    if (myData != NULL)
    {
      if (myData-&gt;bytes != NULL)
        free(myData-&gt;bytes);
      free(myData);
    }
  }
  </code></pre>
  
  <h2>C application</h2>
  
  <p>Main.c</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include "MyLib.h"
  
  void main()
  {
    struct MyData* myData = NULL;
    int length = 100 * 1024 * 1024;
  
    printf("=== C++ test ===\n");
    CreateMyData(&amp;myData, length);
    if (myData != NULL)
    {
      printf("Length: %d\n", myData-&gt;length);
      if (myData-&gt;bytes != NULL)
        printf("First: %d, last: %d\n", myData-&gt;bytes[0], myData-&gt;bytes[myData-&gt;length - 1]);
      else
        printf("myData-&gt;bytes is NULL");
    }
    else
      printf("myData is NULL\n");
    DestroyMyData(myData);
    getchar();
  }
  </code></pre>
  
  <h2>C# application, which uses <code>IntPtr</code> and <code>Marshal</code></h2>
  
  <p>Program.cs</p>
  
  <pre><code>using System;
  using System.Runtime.InteropServices;
  
  public static class Program
  {
    [StructLayout(LayoutKind.Sequential)]
    private struct MyData
    {
      public int Length;
      public IntPtr Bytes;
    }
  
    [DllImport("MyLib.dll")]
    private static extern void CreateMyData(out IntPtr myData, int length);
  
    [DllImport("MyLib.dll")]
    private static extern void DestroyMyData(IntPtr myData);
  
    public static void Main()
    {
      Console.WriteLine("=== C# test, using IntPtr and Marshal ===");
      int length = 100 * 1024 * 1024;
      IntPtr myData1;
      CreateMyData(out myData1, length);
      if (myData1 != IntPtr.Zero)
      {
        MyData myData2 = (MyData)Marshal.PtrToStructure(myData1, typeof(MyData));
        Console.WriteLine("Length: {0}", myData2.Length);
        if (myData2.Bytes != IntPtr.Zero)
        {
          byte[] bytes = new byte[myData2.Length];
          Marshal.Copy(myData2.Bytes, bytes, 0, myData2.Length);
          Console.WriteLine("First: {0}, last: {1}", bytes[0], bytes[myData2.Length - 1]);
        }
        else
          Console.WriteLine("myData.Bytes is IntPtr.Zero");
      }
      else
        Console.WriteLine("myData is IntPtr.Zero");
      DestroyMyData(myData1);
      Console.ReadKey(true);
    }
  }
  </code></pre>
  
  <h2>C# application, which uses <code>unsafe</code> code and pointers</h2>
  
  <p>Program.cs</p>
  
  <pre><code>using System;
  using System.Runtime.InteropServices;
  
  public static class Program
  {
    [StructLayout(LayoutKind.Sequential)]
    private unsafe struct MyData
    {
      public int Length;
      public byte* Bytes;
    }
  
    [DllImport("MyLib.dll")]
    private unsafe static extern void CreateMyData(out MyData* myData, int length);
  
    [DllImport("MyLib.dll")]
    private unsafe static extern void DestroyMyData(MyData* myData);
  
    public unsafe static void Main()
    {
      Console.WriteLine("=== C# test, using unsafe code ===");
      int length = 100 * 1024 * 1024;
      MyData* myData;
      CreateMyData(out myData, length);
      if (myData != null)
      {
        Console.WriteLine("Length: {0}", myData-&gt;Length);
        if (myData-&gt;Bytes != null)
          Console.WriteLine("First: {0}, last: {1}", myData-&gt;Bytes[0], myData-&gt;Bytes[myData-&gt;Length - 1]);
        else
          Console.WriteLine("myData.Bytes is null");
      }
      else
        Console.WriteLine("myData is null");
      DestroyMyData(myData);
      Console.ReadKey(true);
    }
  }
  </code></pre>