gpt4 book ai didi

c# - 将 float[] 作为 ref float 传递给非托管代码是个好主意吗?

转载 作者:太空狗 更新时间:2023-10-29 17:10:12 25 4
gpt4 key购买 nike

我想将 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 代码如何处理 float 很重要:它将把它们视为数组并从 inBuffer 读取值并将值写入 outBuffer。如下所述,问题是在 PInvoke 调用期间是否会固定整个内存?

编辑 2:另一条评论。我故意选择 ref float 因为我也想做这样的事情:

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

在这种情况下应该没有问题,因为无论如何指针都是固定的,但是上面的普通数组的问题仍然存在。

最佳答案

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

如果您需要将 64 个 float 的数组传入和传出原生函数,您有两种选择:

  1. 安排好它。
  2. 使用不安全代码直接固定和传递托管内存。

这是编码方法:

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

请注意,我添加了 [In] 和 [Out] 属性,因为它们告诉编码器 (In) 不要在出路时复制,而 (Out) 不要在进路时复制。始终考虑编写 p/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 能够“在某些情况下”选择固定托管内存,而不是分配非托管内存和复制。问题是:在什么情况下?

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

这对你我来说意味着什么很简单:总是从编码方法开始。如果您遇到性能问题并且探查器告诉您 native 调用消耗了大量时间,那么您可以尝试使用不安全的方法并再次对其进行探查。如果没有明显的改进,那么你唯一的希望就是优化原生调用。

关于c# - 将 float[] 作为 ref float 传递给非托管代码是个好主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10217677/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com