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

时间:2012-04-18 20:44:48

标签: c# c arrays marshalling

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

EXTERN int process_raw(float *inBuffer, float *outBuffer);

在C#中,签名是:

public static extern int process_raw(ref float inBuffer, ref float outBuffer);

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

process_raw(ref someArray[0], ref anotherArray[0])

谢谢!

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

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

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

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

2 个答案:

答案 0 :(得分:4)

你在这里尝试做什么有点含糊不清。本机代码可以将float*视为指向floatfloat值数组的指针。

如果本机代码认为它是指向单个float的指针,那么您的代码就可以了。让float成为本地托管和指针中的ref将正确编组。

如果本机代码认为它是float值的数组,那么您很可能遇到问题。这将在角落的情况下工作,它将其视为长度为1的数组。对于任何其他长度,虽然您需要在托管签名中使用实际数组

public static extern int process_raw(float[] inBuffer, float[] outBuffer);

答案 1 :(得分:4)

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

如果你需要在本机函数中传入64个浮点数组,你有两个选择:

  1. 马歇尔通过。
  2. 使用不安全的代码直接固定并传递托管内存。
  3. 以下是编组方法:

    [DllImport(...)]
    private extern static int process_raw([In] float[] inBuffer, [Out] float[] outBuffer);
    

    请注意,我添加了[In]和[Out]属性,因为它们告诉Marshaller(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);
    }
    

    扩展评论

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

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

    这对你和我意味着什么很简单:始终以编组方法开始。如果您遇到性能问题且分析器告诉您本机调用占用了大量时间,那么您可以尝试使用不安全方法并再次对其进行分析。如果没有明显的改进,那么你只希望优化原生呼叫。