私は文字列のために多くのバイトポインタを使用する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;
}
}
}
これではありません文字列をネイティブコードにマーシャリングする方法 - C APIへの(おそらくP/Invoke)呼び出しの例を投稿できますか? – Justin
私は、ガベージコレクションされたヒープに格納されているとは思わないので、定数文字列が効果的に「固定」されていることを強く疑っています。これに関する証拠の1つは、メソッド本体の一部として提供される定数文字列を使用して、 "Ldstr" ILオペコードを使用して定数文字列がロードされることです。 –
私は以前の声明を明確にすべきです。 "固定ステートメントは、ガベージコレクタが可動変数を再配置するのを防ぎます。固定ステートメントは、安全でないコンテキストでのみ許可されます。固定は、固定サイズのバッファを作成するためにも使用できます。 - http://msdn.microsoft.com/en-us/library/f58wzh21(v=VS.100).aspx - RunUOはとても2010年です:-) –