我想将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]);
}
在这种情况下应该没问题,因为指针仍然是固定的,但上面的正常数组的问题仍然存在。
答案 0 :(得分:4)
你在这里尝试做什么有点含糊不清。本机代码可以将float*
视为指向float
或float
值数组的指针。
如果本机代码认为它是指向单个float
的指针,那么您的代码就可以了。让float
成为本地托管和指针中的ref
将正确编组。
如果本机代码认为它是float
值的数组,那么您很可能遇到问题。这将在角落的情况下工作,它将其视为长度为1的数组。对于任何其他长度,虽然您需要在托管签名中使用实际数组
public static extern int process_raw(float[] inBuffer, float[] outBuffer);
答案 1 :(得分:4)
p / Invoke中没有涉及自动引脚。 P / Invoke严格通过 marshalling 执行! (没有不安全的代码)编组意味着分配(非托管)内存和复制。在封面下,复制期间可能有一个引脚,但在本机函数调用的持续时间内没有。
如果你需要在本机函数中传入64个浮点数组,你有两个选择:
以下是编组方法:
[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时。这只是猜测。
这对你和我意味着什么很简单:始终以编组方法开始。如果您遇到性能问题且分析器告诉您本机调用占用了大量时间,那么您可以尝试使用不安全方法并再次对其进行分析。如果没有明显的改进,那么你只希望优化原生呼叫。