传递一个float []作为ref浮动到非托管代码是一个好主意?

tha*_*alm 7 c c# arrays marshalling

我想将float []传递给C方法.C签名如下:

EXTERN int process_raw(float *inBuffer, float *outBuffer);
Run Code Online (Sandbox Code Playgroud)

在C#中,签名是:

public static extern int process_raw(ref float inBuffer, ref float outBuffer);
Run Code Online (Sandbox Code Playgroud)

将带有ref的数组传递给第一个成员会有问题吗:

process_raw(ref someArray[0], ref anotherArray[0])
Run Code Online (Sandbox Code Playgroud)

谢谢!

编辑:当然重要的是要知道C代码对浮点数的作用:它将它们视为数组,并将从inBuffer读取值并将值写入outBuffer.如下所述,问题是在PInvoke调用期间是否会固定整个内存?

编辑2:另一个评论.我故意选择ref float因为我也想做以下事情:

fixed(byte* outBuff = buffer)
{
    Process(ticks, ref aFloat, ref ((float*)outBuff)[0]);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下它应该没有问题,因为指针仍然是固定的,但上面的正常数组的问题仍然存在.

Ter*_*ver 4

p/Invoke 中不涉及自动固定。P/Invoke 严格通过编组执行!(没有不安全代码)编组意味着分配(非托管)内存和复制。在幕后,可能在复制期间有一个引脚,但在本机函数调用期间没有。

如果您需要将 64 个浮点数的数组传入和传出本机函数,您有两种选择:

  1. 编组它通过。
  2. 使用不安全的代码直接固定并传递托管内存。

这是编组方法:

[DllImport(...)]
private extern static int process_raw([In] float[] inBuffer, [Out] float[] outBuffer);
Run Code Online (Sandbox Code Playgroud)

请注意,我添加了 [In] 和 [Out] 属性,因为它们告诉编组器 (In) 不要在出路时进行复制,而 (Out) 不要在入路时进行复制。 最好在以下情况下始终考虑这些属性:编写 ap/invoke 声明。

这是不安全的方法:

[DllImport(...)]
private extern static unsafe int process_raw(float * inBuffer, float * outbuffer);

public static unsafe int Process(float[] inBuffer, float[] outBuffer)
{
    // validate for null and Length < 64
    fixed (float * pin = inBuffer)
    fixed (float * pout = outBuffer)
        return process_raw(pin, pout);
}
Run Code Online (Sandbox Code Playgroud)

扩展评论

据我了解,编组器能够“在某些情况下”选择固定托管内存,而不是分配非托管内存和复制。问题是:什么情况下?

我不知道答案,但我有一个怀疑:当本机DLL是某些系统DLL时。这只是一个猜测。

这对你我来说意味着非常简单:始终从编组方法开始。如果您遇到性能问题,并且分析器告诉您本机调用消耗了大量时间,那么您可以尝试不安全的方法并再次分析它。如果没有显着的改进,那么您唯一的希望就是优化本机调用。

  • @Tergiver:作为一种优化,Marshaller 将固定而不是复制 blittable 类型,其中包括一维数组。 (2认同)