我有一个 C 库。它有许多函数调用,如下所示:
void init_foo( unsigned long x, unsigned long y );
库本身在运行时动态加载(更像是一个插件)。 header 在所有平台上都是一致的。
我的问题是在 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
我可以使用的 C# 类型在所有平台上都是固定大小的(它们应该是这样)。因此,我从 .Net/Mono 传递的托管 long 将始终是非托管 uint64_t。
我如何处理这个可变的整数大小,同时拥有一个可以在 .Net 或单声道上以 32 位或 64 位模式运行的程序集?
最佳答案
问题在于,在 64 位 Windows 上,C long 仍然是 32 位,而在 Linux 上它是 64 位,这会导致一些痛苦。
如果您不打算支持 64 位 Windows,这很容易 - 您可以在 DllImport 定义中将 long 映射到 IntPtr。 IntPtr在32bit的windows和linux上都是32bit的,和long一样。 Long 在 64 位 Linux 上也是 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 );
然后在您的代码中,您可以在运行时动态决定调用哪一个:
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:如果您不在 .NET 4 上,另一种检查您是否是 64 位进程的方法是 bool is64Bit = IntPtr.Size == 8
关于c# - 处理不同的非托管整数大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5591421/