Geeks With Blogs
.NET Corner Jeans, .NET and Physics (eka The Quantum Boy)

Guys I was busy in some HLD for past two weeks or so. I'm back now into my favourite blogspace  - GWB.

Yesterday when our 64 bit porting team is working for the immediate 64 bit release of our product, they came to me for suggestion on a topic which I think worth discussing. While they are happily ported unmanaged C++ code, they were facing some difficulties with porting managed code(which should be easier! right?). In unmanaged C++ world they handled pointer disparity between the platforms with smart #ifdefs and #define macros. But in managed C# layer we do have some unsafe pointer code that interoperate to the unmanaged C++ code. Situation become tricky. As there is no #define macros in C# world, they were unable to write ubiquitous code that would work on either platform.

In one particular situation we have a long native 64 bit pointer allocated in unmanaged layer and C# unsafe code would like to interoperate with it in following way.

                     ___ ___ ___ ___ ___ ___ ______
x ----------> |___|___|___|___|___|___|___|___|

In 32 bit platform we wanted to access first 4 bytes(32 bit pointer size) of x

... = *((int*)x)

In 64 bit platform ,analogously, we wanted to access first 8 bytes(64 bit pointer size) of x

... = *((__int64*)x)

And in both cases we also used to use integer pointer arithmatic by adding integer offset values to (int*)x or (__int64*)x (which hasn't been shown). No problem as such here. The problem relates to merging these two set of lines to one. I immediately scream "use UIntPtr...". But just how? Well we need to construct a UIntPtr out of the long value - x. In looking through Reflector the specified ctor appears like below

public unsafe UIntPtr(UInt64 value)
{
      this.m_value = (void*) ((uint) value);
}

But mine was a 32 bit CLR. What I guess that in 64 bit this ctor will not truncate the long value. It should be something like below

public unsafe UIntPtr(UInt64 value)
{
      this.m_value = (void*) value;
}

A look into Rotor confirmed my guess. One can check IntPtr.cs file here

public unsafe UIntPtr(UInt64 value)
00051         {
00052             #if WIN32
00053                
m_value = (void *)checked((uint)value);
00054             #else
00055                
m_value = (void *)value;
00056             #endif
00057         }

The consequence is significant. This means m_value holds platform-specific integer pointer and so does the return value of ToPointer() which just exposes the m_value.

public unsafe void* ToPointer()
{
      return this.m_value;
}


So the code should be something like below

UIntPtr uiptr = new UIntPtr(x);   // Invoke the specified ctor
... = *(uiptr.ToPointer());

But the explicit construction of the UIntPtr doesn't look elegant. Then I looked at the following casting operator of UIntPtr which takes a long(64 bit) value and convert it to an UIntPtr -

public static explicit operator UIntPtr(UInt64 value)
{
      return new UIntPtr(value);
}

This conversion operator internally invokes the same ctor we are interested with. So now the revised code looks like

... = *(((UIntPtr)x).ToPointer());
 
64 bit porting of managed application sometimes can create little surprises. When managed code heavily deals with P/Invoke, COM Interop and unsafe(c#) code porting becomes non-trivial. If interested you can look at this official MSDN 32-to-64 bit migration guide for managed code http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/64migrate.asp.

By the way I'm reading two wonderful books  -  both are theoretically non-windows books - "Art of Unix Programming" and "Innovation Happens Elsewhere". Do lots of programming4fun.

Posted on Saturday, November 8, 2008 3:05 AM .NET Core | Back to top


Comments on this post: IntPtr, 64 bit Porting and Fun

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © dbose | Powered by: GeeksWithBlogs.net