2011-07-18 14 views
11

私は文字列のために多くのバイトポインタを使用するBorland C APIを使ってC#で作業しています。私はいくつかのC#文字列を(短命の)バイト*として渡す必要性に直面してきました。定数はC#で固定されていますか?

constオブジェクトはヒープには割り当てられず、プログラムメモリに直接格納されますが、これはどのドキュメントでも確認できませんでした。

ここでは、定数文字列へのポインタを生成するために行った作業の例を示します。これはテストで意図した通りに動作しますが、本当に安全かどうかだけでは不安です。

private const string pinnedStringGetWeight = "getWeight"; 

unsafe public static byte* ExampleReturnWeightPtr(int serial) 
{ 
    fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight)) 
     return pGetWeight; 
} 

このconstは実際に固定されていますか、移動される可能性はありますか?


@Kragen:

ここでは、インポートです:

[DllImport("sidekick.dll", CallingConvention = CallingConvention.Winapi)] 
public static extern int getValueByFunctionFromObject(int serial, int function, byte* debugCallString); 

これは実際の関数です。はい、それは実際には、静的な関数ポインタが必要です。続き

private const int FUNC_GetWeight = 0x004243D0; 

private const string pinnedStringGetWeight = "getWeight"; 

unsafe public static int getWeight(int serial) 
{ 
    fixed (byte* pGetWeight = ASCIIEncoding.ASCII.GetBytes(pinnedStringGetWeight)) 
     return Core.getValueByFunctionFromObject(serial, FUNC_GetWeight, pGetWeight); 
} 

を私のAPIをあざけるとき、私は私も望んが固定された静的な構造体を使用して、使用する別の方法です。私はこれを単純化する方法を見つけることを望んでいた。 ASCIIEncoding.ASCII.GetBytes()は、新しいバイト配列を返すため、それが異なって符号化されているので(それは、定数の内部配列を返すことはできません

定数は、この場合には問題ないはず割り当てられているどのように
public byte* getObjVarString(int serial, byte* varName) 
{ 
    string varname = StringPointerUtils.GetAsciiString(varName); 
    string value = MockObjVarAttachments.GetString(serial, varname); 
    if (value == null) 
     return null; 
    return bytePtrFactory.MakePointerToTempString(value); 
} 

static UnsafeBytePointerFactoryStruct bytePtrFactory = new UnsafeBytePointerFactoryStruct(); 
private unsafe struct UnsafeBytePointerFactoryStruct 
{ 
    fixed byte _InvalidScriptClass[255]; 
    fixed byte _ItemNotFound[255]; 
    fixed byte _MiscBuffer[255]; 

    public byte* InvalidScriptClass 
    { 
     get 
     { 
      fixed (byte* p = _InvalidScriptClass) 
      { 
       CopyNullString(p, "Failed to get script class"); 
       return p; 
      } 
     } 
    } 

    public byte* ItemNotFound 
    { 
     get 
     { 
      fixed (byte* p = _ItemNotFound) 
      { 
       CopyNullString(p, "Item not found"); 
       return p; 
      } 
     } 
    } 

    public byte* MakePointerToTempString(string text) 
    { 
     fixed (byte* p = _ItemNotFound) 
     { 
      CopyNullString(p, text); 
      return p; 
     } 
    } 

    private static void CopyNullString(byte* ptrDest, string text) 
    { 
     byte[] textBytes = ASCIIEncoding.ASCII.GetBytes(text); 
     fixed (byte* p = textBytes) 
     { 
      int i = 0; 
      while (*(p + i) != 0 && i < 254 && i < textBytes.Length) 
      { 
       *(ptrDest + i) = *(p + i); 
       i++; 
      } 
      *(ptrDest + i) = 0; 
     } 
    } 
} 
+1

これではありません文字列をネイティブコードにマーシャリングする方法 - C APIへの(おそらくP/Invoke)呼び出しの例を投稿できますか? – Justin

+1

私は、ガベージコレクションされたヒープに格納されているとは思わないので、定数文字列が効果的に「固定」されていることを強く疑っています。これに関する証拠の1つは、メソッド本体の一部として提供される定数文字列を使用して、 "Ldstr" ILオペコードを使用して定数文字列がロードされることです。 –

+1

私は以前の声明を明確にすべきです。 "固定ステートメントは、ガベージコレクタが可動変数を再配置するのを防ぎます。固定ステートメントは、安全でないコンテキストでのみ許可されます。固定は、固定サイズのバッファを作成するためにも使用できます。 - http://msdn.microsoft.com/en-us/library/f58wzh21(v=VS.100).aspx - RunUOはとても2010年です:-) –

答えて

13

は、(編集:うまくいけば何方法ありません文字列は不変なので、stringの内部配列へのポインタを得るために))。ただし、GCが配列に接触しないことの保証は、fixedスコープが有効である限り、つまり、関数が返ってくるとメモリはもはや固定されません。

+0

これは間違いなく私の質問に答えるものです。これを完全に逃した。本当にありがとう。返されたバイト*は一度返されると完全に信頼できません。私はラッキーになっています。 – Derrick

+0

あなたの質問に答えた場合は、これを回答としてマークする必要があります。 –

+0

@Judah Himango:constが固定されているかどうかのリテラルトピックの質問に答えても、私のコードの正しさについての質問を満たすには十分ですが、わかりません。 – Derrick

1

Kragansのコメントに基づいて、私はバイトポインタにマーシャルに適切な方法に私の文字列を見て、今私は私の質問に使用される最初の例については、以下を使用しています:

 [DllImport("sidekick.dll", CallingConvention = CallingConvention.Winapi)] 
     public static extern int getValueByFunctionFromObject(int serial, int function, [MarshalAs(UnmanagedType.LPStr)]string debugCallString); 
関連する問題