Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将float[]作为ref float传递给非托管代码是一个好主意吗?_C#_C_Arrays_Marshalling - Fatal编程技术网

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

C# 将float[]作为ref float传递给非托管代码是一个好主意吗?,c#,c,arrays,marshalling,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])

我想将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读取值,并将值写入Exputffer。如下所述,问题是在PInvoke调用期间是否会锁定整个内存

编辑2:另一条评论。我特意选择了ref float,因为我也想做如下事情:

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

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

您在这里试图做的事情有点模棱两可。本机代码可以将
float*
视为指向
float
float
值数组的指针

如果本机代码认为它是指向单个
float
的指针,那么您的代码就可以了。将
float
设置为managed中的
ref
,并将指针设置为native将正确封送

如果本机代码认为它是一个由
float
值组成的数组,那么很可能存在问题。这将在拐角处工作,它将其视为长度为1的数组。对于任何其他长度,尽管您需要在托管签名中使用实际数组

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

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

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

  • 马歇尔完成它
  • 使用不安全代码直接锁定和传递托管内存
  • 以下是编组方法:

    [DllImport(...)]
    private extern static int process_raw([In] float[] inBuffer, [Out] float[] outBuffer);
    
    请注意,我添加了[In]和[Out]属性,因为它们告诉封送员(In)不要在输出时复制,而(Out)不要在输入时复制。在编写P/UngEnk声明时总是考虑这些属性是个好主意。 以下是不安全的方法:

    [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);
    }
    
    [DllImport(…)]
    私有外部静态不安全内部处理(浮点*inBuffer,浮点*exputffer);
    公共静态不安全int进程(float[]inBuffer,float[]exputffer)
    {
    //验证是否为空且长度小于64
    固定(浮动*销=缓冲)
    固定式(浮动*pout=exputffer)
    未加工的返回过程(插针、撅嘴);
    }
    
    扩展评论

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

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


    这对你我的意义很简单:总是从封送方法开始。如果您遇到性能问题,并且探查器告诉您本机调用占用了大量时间,那么您可以尝试使用不安全的方法并再次对其进行探查。如果没有显著的改进,那么您唯一的希望就是优化本机调用。

    +1,我想补充一点,OP当前的方法需要手动固定数组,因为封送员不理解它们的意图。(删除了我的答案)@sixlettvariables CLR将在调用期间自动锁定任何传递到PInvoke层的内存。只有当本机指针在PInvoke callI的印象中幸存下来时,才需要pin。ref的to数组元素没有触发该行为(或者认为我的P/Invoke问题与该类代码有关)。@sixlettervariables-hmm,关于
    ref
    的情况,您可能是对的。找到一个支持您需要pin的引用。深入挖掘@sixlettervariables,我发现了更多与那篇文章有争议的来源,并说在PInvoke调用期间,所有传递的内存都被固定。我相信这对于
    ref
    是正确的(否则MS生成的大量示例代码都是错误的)。尽管如此,我仍在四处挖掘,因为这让我相当好奇。如果我发现还有什么有趣的事,我会回信的。注意,您应该考虑重新设计API以包括“IN”和“OUT”缓冲区的大小。特别是当“输出”缓冲区的大小可能与“输入”缓冲区的长度不同时。它还将使封送处理更容易。在这种情况下,很明显,该方法根据定义需要64个样本。但是还有其他类似的方法,它们有一个size参数,但是为了简单起见,它忽略了它们。我唯一关心的是GC和内存是否会被固定。C代码将从inBuffer读取64个值,并将64个值写入Exputffer。谢谢!那么,如果我想公开这两种可能性,我该如何写签名呢?这样程序员就可以使用数组或指针作为参数了?它需要两种实现吗?@Tergiver:作为一种优化,封送器将锁定而不是复制包含1D数组的blittable类型。请参阅上面我的扩展注释@塔姆:我不明白这个问题。你上面有两个签名。