Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling different unmanaged integer sizes

I have a C library. It has many function calls like the following:

void init_foo( unsigned long x, unsigned long y );

The library itself is dynamically loaded at runtime (rather like a plugin). The headers are consistent across all platforms.

My problem is that on windows and 32bit linux, unsigned long is 32bits, yet on 64bit linux this is 64bits.

The various implementations of this library all accept this, you need to build your C program for the right target platform (as expected).

My interop method will need to be one of these depending on the architecture.

#if lin64
[DllImport("libfoo")]
public static void init_foo( Uint64 x, Uint64 y );
#else
[DllImport("libfoo")]
public static void init_foo( Uint32 x, Uint32 y );
#endif

The C# types I can use are fixed size on all platforms (as they should be). So my managed long passed from .Net/Mono will always be an unmanaged uint64_t.

How can I cope with this variable integer size yet have a single assembly that will run on .Net or mono in either 32bit or 64bit mode?

like image 582
IanNorton Avatar asked Apr 08 '11 06:04

IanNorton


1 Answers

The problem is that on 64bit Windows C long is still 32bit unlike on Linux where it's 64bit and that causes a bit of a pain.

If you don't plan to support 64bit Windows it's easy - you can map the long to IntPtr in your DllImport definition. IntPtr is 32bit on both 32bit windows and linux, which is the same as long. Long on 64bit Linux is also 64bit and so is IntPtr, however on Windows 64bit while IntPtr is 64bit long is 32bit.

If you want to support 64bit Windows you can maybe define two signatures at the same time - one for 64bit and one for 32bit like that:

[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_64bit( Uint64 x, Uint64 y );

[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_32bit( Uint32 x, Uint32 y );

Then in your code you can dynamically decide at run-time which one to call like that:

public void InvokeFoo(long x, long y)
{
    if (Environment.Is64BitProcess)
        return init_foo_64bit(x, y);
    return init_foo_32bit((int)x, (int)y);
}

P.S: If you aren't on .NET 4 another way to check if you are a 64bit process will be bool is64Bit = IntPtr.Size == 8

like image 159
Ivan Zlatev Avatar answered Sep 21 '22 03:09

Ivan Zlatev