Click here to Skip to main content
Email Password   helpLost your password?

Introduction

We live in a less than perfect world. If the world were perfect, we could spend our entire time writing managed code and interacting with managed components. (Well, if it were really perfect, we could be sipping tropical cocktails on the ocean beach, but I digress.)

The world that we live in often requires interaction with unmanaged components. Lots has been written on the subject of P/Invoke, COM interop, C++/CLI -- the trifecta of interoperability solutions. In this article, we will look into an apparently trivial scenario. All we are going to do is copy data from one place to another.

Problem Statement

Assume that you have been given an array of bytes containing some structured information. For example, it might be a data structure corresponding to some kind of network packet. You need to parse this array of bytes into a representation that will make it easier to interpret. Unfortunately, there isn't just a single data structure you need -- there's a variety of information types coming as arrays of bytes.

The classical C-style solution of this kind of problem is using a data structure definition and casting the raw memory into an instance of the structure. Since data structures in C are sequential and well-aligned, and since memory manipulation is one of the primary language traits, this all boils down to something as trivial as:

typedef struct t_Packet {
    short Source;
    short Destination;
    int Checksum;
} Packet;

Packet FromRawBytesToPacket(unsigned char* rawBytes) {
    return *(Packet*)rawBytes;
}

This works perfectly in C and C++. But we can't use pointers in C#, can we? Take a couple of minutes to think about this problem. It's a mini-problem. It's a kindergarten problem for a C++ developer. How could it possibly be difficult in managed code?

Remember that one of the primary benefits of a managed environment is that, well, it's managed. You don't take care of memory allocation and deallocation, and as a consequence, the burden of dealing with pointers is removed from your shoulders. With that burden, some additional minor things are removed. This scenario is one of them.

Solution Attempt 1: BinaryReader Approach

Assuming full knowledge about the specific structure of the data, we can use BinaryReader -- a class perfectly suited for reading primitive types from a binary form. Here's a first attempt at a solution:

struct Packet
{
    public short Source;
    public short Destination;
    public int Checksum;
}

static Packet ReadUsingBinaryReader(byte[] data)
{
    Packet packet;
    using (BinaryReader reader = new BinaryReader(new MemoryStream(data, false)))
    {
        packet.Source = reader.ReadInt16();
        packet.Destination = reader.ReadInt16();
        packet.Checksum = reader.ReadInt32();
    }
    return packet;
}

This doesn't look so bad, now does it? However, considering that I might need a hundred structures like this one, and the structures are going to change every couple of weeks, maintaining this kind of solution becomes a nightmare. (As a side note, it's always possible to automate the process by generating the necessary code from the structure definition. It's not trivial, because structures can be nested recursively, but doable, and I will leave it as an exercise for the reader.)

Unfortunately, maintainability is not the only problem with this code. The performance is not spectacular either. Reading 1,000,000 instances of this trivial data structure takes 490 milliseconds on my test machine. That's quite a lot of time, and it caps our throughput at about 2 million messages per second. Sometimes it's a lot -- at other times, it isn't.

Solution Attempt 2: A Generic Approach

A generic approach to this problem requires a generic method that accepts an array of bytes and returns an instance of a generic type parameter. However, in order to do that, we need a mechanism that will automatically read the binary representation of our structure fields. The framework happens to have a mechanism handy for doing just that, in a generic fashion, as part of the System.Runtime.InteropServices.Marshal class.

The Marshal class has an interesting method called Marshal.PtrToStructure, which seems to be a good match for our scenario. The documentation discusses marshaling from an unmanaged block of memory, but why would our raw byte array be any worse than an unmanaged block of memory? All we need to do is figure a way to comply with the signature: object PtrToStructure(IntPtr, Type). This IntPtr there is annoying -- it means we have to find the memory address of our byte array.

The intrinsic facility for finding the memory address of a managed object is the GCHandle structure. Why are there special precautions we need to take when obtaining the address of a managed object? Well, the primary precaution is that the managed object can move in memory! During garbage collection, it's perfectly natural for a managed object to be shifted around, and we certainly can't have that happening if we need a stable memory address for our object. This is alleviated by allocating a GCHandleType.Pinned handle, which will ensure the object isn't shifted in memory by the garbage collector.

Eventually, we come up with the following implementation:

static T ReadUsingMarshalSafe<T>(byte[] data) where T : struct
{
    GCHandle gch = GCHandle.Alloc(data, GCHandleType.Pinned);
    try
    {
        return (T)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(T));
    }
    finally
    {
        gch.Free();
    }
}

Note that if the GCHandle is not explicitly freed, we will have a memory leak. Since the handle is a value type, it doesn't have a finalizer or any implicit mechanism for unpinning and freeing the memory.

This is a generic solution, and one that works for any blittable data structure -- not only our Packet as defined earlier. However, its performance characteristics are below par -- 850 milliseconds for a million objects, almost twice as slow as the BinaryReader solution.

On the one hand, we have a specifically-tailored solution which gives us the best performance. On the other hand, we have a generic solution which is almost two times slower. What can possibly be improved?

Solution Attempt 3: Unsafe Non-Generic Approach

Well, it appears that we can use pointers from C# after all. Unsafe code is not one of the well-known or best-advertised features of the CLR, but there is nothing inherent in its design or implementation to prevent us from directly accessing memory via pointers.

To begin with, we need to compile our project with the /unsafe switch. Its Visual Studio equivalent is under the Project Properties, Build, Allow unsafe code checkbox. Next, whenever we use a pointer, we will need to wrap the code using it in an unsafe block. These are minor nuisances, however -- let's take a look at a possible solution:

static Packet ReadUsingPointer(byte[] data)
{
    unsafe
    {
        fixed (byte* packet = &data[0])
        {
            return *(Packet*)packet;
        }
    }
}

Is that all? Yes, that's all! The fixed statement makes sure the byte array is pinned and its address is available, and the single return statement inside the block casts the byte* around to obtain a Packet instance.

What about performance? That's where this solution really shines: 13 milliseconds for a million instances, 65 times faster than Marshal.PtrToStructure and 37 times faster than BinaryReader! The only setback is that this code is not generic, but what stops us from changing this fact?

Solution Attempt 4: Unsafe Generic Approach

A naive attempt at a generic solution using C# pointers would be something along the following lines:

static T ReadUsingPointer<T>(byte[] data) where T : struct
{
    unsafe
    {
        fixed (byte* packet = &data[0])
        {
            return *(T*)packet;
        }
    }
}

Unfortunately, this doesn't compile, complaining that our code "Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')". What's wrong with our code? Just one thing -- we are assuming that T is a type that we can declare a pointer to. And not every type is that kind of pointer-friendly type. Specifically, the only types we are allowed to declare a pointer to are:

Why does the compiler complain then? Because we are writing a generic method, and the compiler must be satisfied that any type T that our users might use will be a type that we are allowed to point at. But since there is no generic constraint for expressing that, the compiler is never going to accept our code as it is.

Now we stand at a crossroad. If we're looking for a specific solution for a specific data structure, then this might be enough. We don't need a generic method. But if we have multiple data structures, we might at least attempt to improve upon the Marshal.PtrToStructure approach, armed with our knowledge of pointers:

static T ReadUsingMarshalUnsafe<T>(byte[] data) where T : struct
{
    unsafe
    {
        fixed (byte* p = &data[0])
        {
            return (T) Marshal.PtrToStructure(new IntPtr(p), typeof(T));
        }
    }
}

Why is this any better than using a GCHandle? Because internally, the code generated for the fixed statement is more efficient than using a GCHandle. Specifically, the emitted IL will contain a so-called pinned pointer, which is a short-circuit pinning mechanism.

Namely, the performance improvement is significant: 555 milliseconds for a million instances, only slightly slower than the BinaryReader approach.

We might be ready to give up at this point. Either embrace pointers and accept the lack of genericity, or use Marshal.PtrToStructure and accept the poor performance. But remember what we had in mind in the beginning, the C-style solution to this problem? If we can't cleanly solve this in C#, why don't we cleanly solve it in... C++/CLI?

Solution Attempt 5: C++/CLI Approach

C++/CLI is a managed programming language based on C++. In fact, it's a set of extensions to the standard C++ syntax, so everything you know about C++ is true for C++/CLI. This is neither the time nor the place to elaborate about C++/CLI, but its primary usage scenario is interoperability. One of my blog articles elaborates on the usefulness of C++/CLI as a bridging mechanism between native and managed code, in both directions.

However, we aren't really interested in the interoperability scenario. We're looking at improving the performance of our solution. As it appears, C++/CLI can be used for performance reasons where C# doesn't give us the necessary facilities for the fastest possible solution. What we are going to do is write the actual copying code in C++/CLI, and call it from C#. Since even C++/CLI won't let us declare a direct pointer to a generic parameter, we will outsmart it and use memcpy:

public ref class Reader abstract sealed
{
public:
    generic <typename T> where T : value class
    static T Read(array<System::Byte>^ data)
    {
        T value;

        pin_ptr<System::Byte> src = &data[0];
        pin_ptr<T> dst = &value;

        memcpy((void*)dst, (void*)src,
            /*System::Runtime::InteropServices::Marshal::SizeOf(T::typeid)*/
            sizeof(T));

        return value;
    }
};

This appears to be very different from your common C# code, but it's not that different after all. Some highlights:

Note that we could either use Marshal.SizeOf or the built-in sizeof operator. If the structure had any elements without straightforward marshaling (such as characters), sizeof might have been inaccurate -- but it's significantly faster.

How is the performance? With no significant optimizations, this code performs at 60 milliseconds for a million instances. That's blazingly fast, even though still 4 times slower than the trivial C# pointer manipulation in the non-generic case. The primary cost factor here is the interop transition -- after all, we're calling from C# through C++/CLI to the hand-coded assembler implementation of memcpy. The costs of this transition will be smaller if the structure is bigger, or if we can introduce an implementation that performs multiple reads on the native side. But even as is, it's clear that we have a solution that is both fast and generic. It's not the fastest one, but it's significantly better than the other generic solutions.

Consolidation

Summing this up, we have looked at multiple solutions for a problem that seemed really simple at first -- copying a chunk of data from raw memory into a data structure. I feel that taking a language and a framework to its limits, and then crossing these limits, provides the best insight into what's possible in your code.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralA more simplistic approach using emit
floste
11:37 26 Jan '10  
http://www.mycsharp.de/wbb2/thread.php?threadid=80915[^]
The only thing i emit is a method taking a ref parameter wich is in fact already a pointer. The Method just casts this pointer to void* and returns it. Quite simple. Big Grin
GeneralGeneric code-generation method has been implemented
nyurik
22:35 13 Feb '09  
Hi, I have implemented a dynamic code generation project of byte-to-user_struct method, and added it to your project here: http://www.codeproject.com/KB/cs/ReadingStructuresEmit.aspx. The performance is comparable to the fixed() method, and much faster than the C++ method. Please take a look and possibly update your code from the sample. Thanks for the good article!
GeneralSolution 6
Ralph Varjabedian
3:35 29 Jul '08  
Using the Emit namespace, I have created a solution that creates classes at runtime using IL code that use the BinaryReader to cast the byte array into your structures.

Take a look at this post:
http://varjabedian.net/archive/2008/07/29/casting-a-byte-array-into-structures-in-c.aspx

Hope this helps. Regards.

Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Solution 6
Sasha Goldshtein
10:13 30 Jul '08  
It's a great sample of using code generation to achieve better performance at runtime, but while you're at it, you can generate code to use pointers (which will certainly outperform BinaryReader because the heavy-lifting will be done by the JIT). I realize that you're looking for a solution that will work in VB.NET as well, but you can always wrap it in an assembly and use that from VB.NET.
GeneralRe: Solution 6
Ralph Varjabedian
0:23 31 Jul '08  
Generating code to do use pointers does not give performance benefits than writing code at compile time to do that. The point of generating code is to get rid of reflection which is slow.

So if someone wants to use casting pointers, just go ahead and write its code directly at compile time.

Thanks for sharing.
Regards.



Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Solution 6
Sasha Goldshtein
20:34 31 Jul '08  
I'm afraid that we don't understand each other. What I'm saying is that you can't write a generic compile-time method that looks like this:


T Read(byte[] data) {
fixed(byte* p = &data[0]) { return *(T*)p; }
}


...because there is no generic constraint to satisfy the fact that you can declare a pointer to a C# type. Instead, you can use code generation to generate specific versions for each type:


T Read(byte[] data) {
Reader r = GenerateTheCodeAndCompileIt();
return r(data);
}
//where the generated code is similar to what I wrote above for each specific T you get

GeneralRe: Solution 6
Ralph Varjabedian
23:51 31 Jul '08  
Ok, I see what you mean there. I got you wrong. Yes this can be done. But what is the advantage of this compared to the advantage of writing the same method without being Strongly typed and then simply casting to the appropriate type in your code. There is no advantage right? And also to write code at runtime, usually I write code that implements a certain Interface (defined at compile time) so we are back at square one, considering that the Interface that I will write at compile time would not be strongly typed for the specific type that you want to cast...

Regards.

Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Solution 6
Sasha Goldshtein
4:49 1 Aug '08  
You can generate code to implement Read<T> as a generic method, by generating a method to use T* for the copy and invoke it through a delegate T Reader<T>(byte[] data) to remain strongly typed.
GeneralRe: Solution 6
Ralph Varjabedian
5:08 1 Aug '08  
yes, but my question remains Smile

But what is the advantage of this (runtime generated) compared to the advantage of writing the same method (compile time) without being Strongly typed and then simply casting to the appropriate type in your code.

Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Solution 6
Sasha Goldshtein
5:16 1 Aug '08  
I'm sorry, I don't understand what you mean. How can you write this method at compile-time? To produce a pointer to a type, you need the specific type.
GeneralRe: Solution 6
Ralph Varjabedian
5:41 1 Aug '08  
Ok, I see your point here, you are right... It is worth researching as a solution using Emit namespace. It is a good option, what are the disadvantages of using fixed? Is it worth using unsafe code?

Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Solution 6
Sasha Goldshtein
6:28 1 Aug '08  
As the article demonstrates, it's certainly worth it performance wise, because the JIT does all the work and you get the most efficient code possible for reading the structure fields one after the other.

As for disadvantages of fixed - if you know what you're doing, unsafe code is sometimes the only option. fixed requires pinning, but it's cheap in this case because the work performed under the pin is very short and therefore the chances of a GC in the middle are slim.
GeneralHave you tried this one?
Neverbirth
14:14 25 Jun '08  
Just for the sake of completeness... have you tried using the CopyMemory API?

Nice article.
GeneralRe: Have you tried this one?
Sasha Goldshtein
0:37 27 Jun '08  
If you mean instead of memcpy, then no, I haven't - but I suspect there's hardly going to be any performance difference.

By the way, from my experience, the fastest way to copy bytes around on Intel processors is using Intel's own library - IPP.
Questionproblem with returing structure ponter
cristi_alonso
2:10 20 Jun '08  
Hi sasha.very   nice article about unamanaged data.
I have some problem regarding unmanaged data.
I wrote code to access structre from C# .net where structure is in C dll .when i debug the code i got garbage value in the variables.
here are the two files .

------------------------- StrcutreDisplay.dll---------------------------------

#include<iostream.h>

#include<conio.h>

#include<malloc.h>

#include<string.h>

extern "C"

{

typedef struct

{

char *fname;

char *lname;

}Detail;




__declspec(dllexport) Detail * Disp()

{

Detail *ptr=(Detail *)malloc(sizeof(Detail));

ptr->fname = (char*)malloc(50);

memset(ptr->fname, 0x00, 50);

ptr->lname = (char*)malloc(50);

memset(ptr->lname, 0x00, 50);

strcpy(ptr->fname, "larson");

strcpy(ptr->lname, "scolari");

return ptr;

}

}


----------------------------StructureExample---------------------------------





using System;

using System.Collections.Generic;

using System.Text;

using System.Runtime.InteropServices;

namespace StructureExample

{

class Program

{

[StructLayout(LayoutKind.Explicit)]

public struct Detail

{ // [MarshalAs(UnmanagedType.LPStr)]

[FieldOffset (0)]public unsafe char* fname;

[FieldOffset(4)]public unsafe char* lname;

}





// strucure DLL

[DllImport("StructureDisplay.dll")]

public static unsafe extern Detail * Disp();

static void Main(string[] args)

{

unsafe

{

Detail * var = Disp();

char* a = var->fname;      //here i get   garbage value and the value of this expression may be      incorrect.it could not be evaluated because 'Cannot derefrence'(*var).fname' the pointer is not valid.

char* b = var->lname; // 'Cannot derefrence'(*var).lname' the pointer is not valid.


}


// IntPtr por = Disp();


//unsafe

//{

// Detail* ger;

// ger =(Detail )Marshal.PtrToStructure(por,typeof(Detail ));

//}

Console.WriteLine("hello world");

Console.Read();

}

}

}


------------------------------------------------------------------------------------------------

when i access that dll from c it works fine but through .net i get some garbage value.when   i   tried to convert char * to string   by using a method of Marshal class (ptrToStringAuto() or ptrToStringAnsi())that time also i get some garbage value.My main   question is why i am getting garbage value in char * a and char * b.Please help me to solve that problem.






Any help appreciated.
Thanks in advance. Smile
AnswerRe: problem with returing structure ponter
Sasha Goldshtein
22:41 20 Jun '08  
First of all, I hope you realize that this is not a support forum. There are numerous forums on the web (including CodeProject Forums and the Microsoft MSDN Forums) where you could have got a faster and possibly more accurate reply from a significantly larger audience.

With that in mind, I can think of multiple reasons for your code to fail. To begin with, since (for some reason) you're using FieldOffset in your structure, it will not work on 64-bit, where the pointer size is 8 bytes. Assuming that this isn't the issue: Your C code is creating a character array with ANSI characters (strcpy and such), but you're treating them as a Unicode character pointer in your C# code. Since you're declaring pointers explicitly, there's no marshaling to save you, and you're essentially looking at garbage. Change your struct to:


struct Detail
{
public unsafe sbyte* fname;
public unsafe sbyte* lname;
}


And read the strings from it using the string constructor that takes an sbyte*:


Detail* detail = Disp();
string a = new string(detail->fname);
string b = new string(detail->lname);

GeneralThanks, but a little bit late ;-)
Alex Cohn
21:15 3 Jun '08  
I was using a similar approach to convert network packets to C# structures (which reflected 1:1 structures in the C++ unmanaged client-side application). Specifically, I was using Marshal.UnsafeAddrOfPinnedArrayElement() to point to the byte I needed. This worked like charm on the test server, but was found to crash the production server in most brutal and unpredictable ways. The product under development was an Internet billiard game, which was lagging far behind the schedule, and after desperate and futile attempts to find the cause of our troubles, we hired an external expert; he spent a couple of long nights before, by accident, the issue of sending binary data over the network was mentioned.

The expert pushed us to convert all our networking protocol to use XML, which we did, in the end... Loosing on performance, for sure, and on maintenance (in addition to keeping in sync the struct definitions on C++ and C# sides, we now had the serialize to XML and from XML methods for each type).

But this definitely gave us additional flexibility, to make network packets more intelligible for debugging, to have the C# structures on the server side diverge, if necessary, from their native counterparts... And in the end, we only wasted a couple of weeks to complete the shift.

Now, the question: do you happen to remember the expert's name, by any chance? Laugh
GeneralRe: Thanks, but a little bit late ;-)
Sasha Goldshtein
6:29 4 Jun '08  
Heh, Alex, funny to read your comment here. (For the rest of the readers, the expert Alex is talking about is me.)

The most politically correct thing I can say is that the approach above should be used with caution. It is unsafe, and it's extremely easy to corrupt memory in this fashion. However, in the past and present I have been part of projects that needed this "unsafety" for its performance benefits. And it is possible to use unsafe code and still have a reliable system - it just takes significantly more validation and error isolation.
GeneralRe: Thanks, but a little bit late
Alex Cohn
7:00 4 Jun '08  
So, if we leave the funny piece aside, what is the meaning of unsafe in your reply, and in the method name? There was no problem with my code in single-client testing environment, but some very unpleasant crashes happened randomly when the server was under (minor) load. There was no direct connection, as far as I can recall, between the crashes and the calls to Marshal.UnsafeAddrOfPinnedArrayElement(). The fact is, after we switched to XML parsing and fixed all the bugs in that mechanism, the crashes of the type you were asked to analyze, were gone.
GeneralRe: Thanks, but a little bit late
Sasha Goldshtein
0:21 14 Jun '08  
Alex, when the crashes occur within CLR code that accesses array elements, and coincidentally you're using Marshal.UnsafeAddrOfPinnedArrayElement which doesn't even validate that the array is indeed pinned, there's enough reason for suspicion.

If you would like to continue this discussion, which IMHO is of no interest to the rest of the readers, please feel free to contact me by email or through my blog.

I appreciate your comments.
General[Modified] Nice - but structure layout
geo_m
4:38 14 May '08  
Very nice article, there's nothing much to add to Wink. You got my 5...

But I would strongly recommend to add the StructLayoutAttribute to the Packet structure that is being read, with LayoutKind.Sequential or even better LayoutKind.Explicit.

Otherwise the framework is free to set the actual structure alignments and even the order of members in the memory, based on processor architecture or whatever optimization criteria it can have (and it can even change in future).

Such a change would lead to very subtle bugs that are difficult to diagnoseFrown

And when you decide to use, it's better to declare the structures using the specific types like UInt32, UInt16 etc.

good job anyway!
GeneralRe: [Modified] Nice - but structure layout
Sasha Goldshtein
5:10 14 May '08  
The C# compiler applies the [StructLayout(LayoutKind.Sequential)] to structures by default: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx[^]
GeneralRe: [Modified] Nice - but structure layout
geo_m
5:21 14 May '08  
Ah, I overlooked that. Then it's better Wink
GeneralRe: [Modified] Nice - but structure layout
geo_m
5:29 14 May '08  
but anyway for parsing packets (I assume some network or similar packets) the LayoutKind.Explicit is the best choice.
GeneralRe: [Modified] Nice - but structure layout
Sasha Goldshtein
5:36 14 May '08  
It's the best choice if you need to control the layout explicitly.


Last Updated 8 May 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010