处理不同的非托管整数大小

Ian*_*ton 8 .net c# mono integer unmanaged

我有一个C库.它有许多函数调用,如下所示:

void init_foo( unsigned long x, unsigned long y );
Run Code Online (Sandbox Code Playgroud)

库本身在运行时动态加载(而非插件).标头在所有平台上都是一致的.

我的问题是在Windows和32位linux上,unsigned long是32位,而在64位linux上这是64位.

这个库的各种实现都接受这个,你需要为正确的目标平台构建你的C程序(如预期的那样).

我的互操作方法需要是其中之一,具体取决于架构.

#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
Run Code Online (Sandbox Code Playgroud)

我可以使用的C#类型在所有平台上都是固定大小的(因为它们应该是).所以我从.Net/Mono传来的托管长期将永远是一个非托管的uint64_t.

我如何处理这个可变整数大小但是有一个程序集可以在.Net或单声道上以32位或64位模式运行?

Iva*_*tev 4

问题是,在 64 位 Windows 上,C long 仍然是 32 位,而在 Linux 上是 64 位,这会带来一些麻烦。

如果您不打算支持 64 位 Windows,这很简单 - 您可以在 DllImport 定义中将 long 映射到 IntPtr。IntPtr在32位windows和linux上都是32位的,和long是一样的。在 64 位 Linux 上,Long 也是 64 位,IntPtr 也是 64 位,但是在 Windows 64 位上,IntPtr 是 64 位,long 是 32 位。

如果你想支持 64 位 Windows,你可以同时定义两个签名 - 一个用于 64 位,一个用于 32 位,如下所示:

[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 );
Run Code Online (Sandbox Code Playgroud)

然后在您的代码中,您可以在运行时动态决定调用哪一个,如下所示:

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

PS:如果您不在 .NET 4 上,则检查您是否是 64 位进程的另一种方法是bool is64Bit = IntPtr.Size == 8