8

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:別のコメント。次のようなこともしたかったので、意図的にreffloatを選択しました。

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

この場合、ポインタはとにかく固定されているので問題はありませんが、上記のような通常の配列の問題は残ります。

4

2 に答える 2

4

ここでやろうとしていることは少しあいまいです。ネイティブコードは、をまたは値の配列float*へのポインタとして扱っている可能性があります。floatfloat

ネイティブコードがシングルへのポインタであると判断したfloat場合、コードは問題ありません。を管理対象にし、ポインタをネイティブにするとfloatref正しくマーシャリングされます。

ネイティブコードがfloat値の配列であると判断した場合は、問題が発生している可能性があります。これは、長さ1の配列として扱われるコーナーケースで機能します。他の長さの場合は、管理対象の署名で実際の配列を使用する必要があります。

public static extern int process_raw(float[] inBuffer, float[] outBuffer);
于 2012-04-18T20:48:27.087 に答える
4

p/Invokeに関係する自動ピンはありません。P / Invokeは、マーシャリングを介して厳密に実行されます。(安全でないコードなしで)マーシャリングとは、(管理されていない)メモリを割り当ててコピーすることを意味します。カバーの下には、おそらくコピーの期間中はピンがありますが、ネイティブ関数呼び出しの期間中はピンがありません。

64個のfloatの配列をネイティブ関数に出し入れする必要がある場合は、次の2つの選択肢があります。

  1. それをマーシャルします。
  2. 安全でないコードを使用して、管理対象メモリを直接固定して渡します。

マーシャリングされた方法は次のとおりです。

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

[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);
}

拡大コメント

マーシャラーは、「特定の状況下で」、アンマネージメモリを割り当ててコピーする代わりに、マネージメモリを固定することを選択できることを理解しています。それに関する問題は次のとおりです。どのような状況ですか?

答えはわかりませんが、疑わしい点があります。ネイティブDLLが特定のシステムDLLである場合。それは単なる推測です。

これがあなたと私にとって何を意味するかは非常に単純です。常にマーシャリングされた方法から始めます。パフォーマンスの問題が発生していて、プロファイラーがネイティブコールにかなりの時間を費やしていると通知した場合は、安全でない方法を試して、プロファイリングをやり直すことができます。大幅な改善がない場合は、ネイティブコールを最適化することだけが期待されます。

于 2012-04-18T22:24:07.333 に答える