2012-04-18 9 views
7

フロート[]をCメソッドに渡したいと思います。 C署名は次のようになりますfloat []を参照floatとしてアンマネージドコードに渡すと良いアイデアですか?

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

C#で署名である:

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

は、第1部材にREFと配列を渡すことは問題であろう。

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

おかげ!

EDIT:もちろん、Cコードが浮動小数点で何をするかを知ることは重要です。それは配列として扱い、inBufferから値を読み込み、値をoutBufferに書き込みます。以下で説明するように、PInvoke呼び出し中にメモリ全体が固定されるかどうかという疑問があります。

EDIT 2:もう1つのコメント。それは問題になりません。この場合、

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

ポインタがとにかく固定されているので、しかし、上記の遺跡として通常の配列のための質問:私は、私も同じようなことをやってみたかったので、目的の参照フロートを選びました。

+1

"in"と "out"バッファのサイズを含めるようにAPIを再設計することを考慮する必要があります。特に、 "out"バッファのサイズが "in"バッファと異なる長さになる可能性がある場合。また、マーシャリングも容易になります。 –

+0

この場合、そのメソッドは64サンプルを定義します。このようなサイズ引数を持つ他のメソッドがありますが、単純化のためにそれらを残しました。私の唯一の関心事はGCであり、メモリが固定されているかどうかです。 CコードはinBufferから64個の値を読み込み、outBufferに64個の値を書き込みます。 – thalm

答えて

4

で実際の配列を使用する必要があるもののPに関わる一切の自動ピンはありません、他の長さについては長さ1の配列として扱いコーナーケースで動作します呼び出します。 P/Invokeは、マーシャルによって厳密に実行されます。 (安全でないコードなし)マーシャリングとは、(管理されていない)メモリとコピーを割り当てることを意味します。カバーの下には、おそらくコピーの持続時間のピンがありますが、ネイティブ関数呼び出しの持続時間はありません。

  1. マーシャルそれを通過:あなたがしてネイティブ関数のうち64個のfloatの配列を渡す必要がある場合

    は、次の2つの選択肢があります。

  2. 安全でないコードを使用して、マネージメモリを直接ピン接続して渡します。ここで

整列化された方法であって、外の方法でコピーして(アウトしない(で)私は、彼らがマーシャラーを伝えるように]および[アウト]は属性を追加

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

注意)途中でコピーしないでください。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であると疑いがあります。それは単なる推測です。

これはあなたと私にとって非常に簡単なことです:常にマーシャリングされたメソッドから始めてください。パフォーマンスに問題があり、プロファイラがネイティブコールがかなりの時間を費やしていると伝えている場合は、安全でない方法を試してもう一度プロファイルすることができます。重要な改善がない場合は、ネイティブコールを最適化するだけでよいでしょう。

+0

ありがとうございます!だから私は両方の可能性を暴露したい場合は、署名を書くだろうか?プログラマは引数として配列またはポインタを使用できますか? 2つの実装が必要でしょうか? – thalm

+2

@Tergiver:最適化として、1D配列を含むblittable型のコピーではなく、Marshallerがピンで固定されます。 – user7116

+0

上記の拡張コメントを参照してください。 @thalm:私はその質問を理解していない。上記の両方の署名があります。 – Tergiver

4

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

ネイティブコードが単一のポインタfloatへのポインタだと思うなら、コードは問題ありません。 floatrefで管理し、ネイティブのポインタを正しくマーシャリングします。

ネイティブコードでは、それがfloat値の配列だと思う場合は、おそらく問題があります。これは、/あなたが管理し、署名

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

+1、OPの現在のアプローチでは、Marshallerが意図を理解できないため、配列を手動で固定する必要があります。 (私の答えを削除しました) – user7116

+0

@sixlettervariables CLRは、呼び出しの間PInvokeレイヤーに渡されるメモリを自動的に固定します。ピンは、ネイティブポインターがPInvoke呼び出しを引き継ぐ場合にのみ必要です。 – JaredPar

+0

配列要素への印象参照の下で、その動作を引き起こさなかった(またはP/Invokeの問題がその種類のコードに関係していると信じていました)。 – user7116

関連する問題