2011-07-18 31 views
11

Ben dizeleri bayt olduğu bir sürü kullanan bir Borland C API ile C# çalışıyorum. Bazı C# dizeleri (kısa ömürlü) bayt * olarak geçirme ihtiyacı ile karşı karşıya kaldım.C# sabitlenmiş sabitler var mı?

Bir const nesne öbek üzerinde tahsis olmaz, ancak program bellekte depolanmasını olurdu, ama herhangi belgelerinde bu doğrulayamadığınız ettik benim doğal varsayım olurdu.

Burada sabit bir dizeye bir işaretçi üretmek için ne yaptık bir örnek. Bu testte amaçlandığı gibi çalışıyor, gerçekten güvenli olup olmadığından emin değilim, ya da sadece şansla çalışıyor.

private const string pinnedStringGetWeight = "getWeight"; 

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

Bu const gerçekten sabitlenmiş mi, yoksa taşınması mümkün mü?


@Kragen:

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

Bu gerçek fonksiyonudur: Burada

ithalatı. Evet, aslında bir statik işlev işaretçisi gerektirir:

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

ardından ben de çivilenmişti ümit statik yapı kullanılarak, benim API alay ederken kullanılan diğer bir yöntemdir. Bunu basitleştirmek için bir yol bulmayı umuyordum. ASCIIEncoding.ASCII.GetBytes() yeni bayt dizisi döndürür çünkü farklı şekilde kodlanmış olduğundan (bu sabitin iç diziyi döndüremez

sabitleri bu durumda önemli olmamalı nasıl ayrılır?
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

Bu değil Yerel kod için marşal dizeleri yolu - C API'nize (muhtemelen P/Invoke) bir çağrı gönderebilir misiniz? – Justin

+1

Sabit dizelerin etkin bir şekilde "sabitlendiğinden" şüpheleniyorum, çünkü çöp yığınında birikmiş yığınlarda saklandıklarına inanmıyorum. Bunun bir kanıtı, sabit dizelerin, "Ldstr" IL opcode kullanılarak, yöntem gövdesinin bir parçası olarak sağlanan sabit dizgeyle yüklenmesidir. –

+1

Önceki ifademi açıklığa kavuşturmalıyım. "Sabit ifade, çöp toplayıcısının hareketli bir değişkeni yeniden konumlandırmasını engeller. Sabit ifadeye yalnızca güvenli olmayan bir bağlamda izin verilir. Sabit, sabit boyutlu tamponlar oluşturmak için de kullanılabilir." - http://msdn.microsoft.com/en-us/library/f58wzh21(v=VS.100).aspx - RunUO böylece 2010 :-) –

cevap

13

, (düzenleme: umarım hiçbir yolu yoktur string'un iç dizisine bir işaretçi almak için, dizeler değişmez olduğundan)). başka bir deyişle, işlevin döndürdüğü bellek artık sabitlenmiş zaman - Ancak, GC dizi dokunmaz garanti sadece sürece fixed kapsamı yaptığı gibi sürer.

+0

Bu kesinlikle sorumu cevaplar. Bunu tamamen özledim. Çok teşekkürler. İade ettiğim bayt * bir kez geri döndüğünde tamamen güvenilmez, şanslı oldum. – Derrick

+0

Sorunuza cevap verirse, bunu yanıt olarak işaretlemelisiniz. –

+0

@Judah Himango: Bu cevabın kendi kodumun doğruluğu ile ilgili soruyu tatmin etmek için tamamen yeterli olmasına rağmen, maddi duran kıstasların ne yapılacağına dair gerçek konu sorusu yanıtlanıp karşılanmadığından emin değilim. – Derrick

1

Kragans açıklama dayanarak, bir bayt işaretçi Marshall'a uygun şekilde içine benim dize baktım ve şimdi Sorumun kullanılan ilk örneğin aşağıdaki kullanıyorum:

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