簡體   English   中英

從C#調用非托管函數:我應該傳遞StringBuilder還是使用不安全的代碼?

[英]Calling unmanaged function from C#: should I pass StringBuilder or use unsafe code?

我有一個C#程序需要將char緩沖區傳遞給非托管函數。 我發現兩種似乎可靠的方法,但我不確定我應該選擇哪種方式。

這是非托管功能的簽名。

extern "C" __declspec(dllexport) int getNextResponse(char *buffer);

第一個選項是將緩沖區定義為StringBuilder,如下所示。

//at class level...
[DllImport("mydll.dll")]
static extern int getNextResponse(StringBuilder buffer);

//in main method body...
StringBuilder sb = new StringBuilder(" ", 65536);
int rc = getNextResponse(sb);

這很簡單,並且它可以工作,我想我基本上理解它為什么會起作用,因為StringBuilder在幕后有一個緩沖區,所以(我假設)interop層只是將StringBuilder編組為char *。

另一種選擇是使用不安全的代碼。

//at class level...
[DllImport("mydll.dll")]
static extern int getNextResponse(byte* buffer);

//separate method...
private static unsafe int runGetNextResponse(byte[] buffer)
{
    fixed (byte* p = buffer)
    {
        int rc = getNextResponse(p);
        return rc;
    }            
}

//in main method body...
byte[] b = new byte[65536];
int rc = runGetNextResponse(b);

第二種方法是更多的代碼,但它也更明確地發生了什么。

這兩種方法基本上是一樣的嗎? 有沒有理由選擇一個而不是另一個?

我非常喜歡使用StringBuilder版本。

這兩者之間不會有太大的區別,使用不安全的代碼並不是那么干凈。

在我看來,由於有一種方法可以使用核心庫類來解決問題,因此使用不安全的代碼而沒有明確(並且需要)的好處是過早的優化。

雖然首選使用StringBuilder,但有一點需要注意。 例如,想象一下,在你的getNextResponse方法中,你將指針存儲到某個靜態變量並在另一個方法中使用它:

char* globalPointer;

int getNextResponse(char *buffer) {
    globalPointer = buffer;
    return 0;
}

void someOtherMethod() {
    printf("%s\n", globalPointer);
}

現在讓我們看一下管理方面:

var sb = new StringBuilder();
sb.Append("Hello World");
int result = getNextResponse(sb);
Console.WriteLine(result);
someOtherMethod(); // kaboom: The GC could have already destroyed the string builder.

不安全的方法可以保證您不會移動內存位置:

byte[] buffer = Encoding.UTF8.GetBytes("Hello World");
fixed (byte* p = buffer)
{
    int result = getNextResponse(p);
    Console.WriteLine(result);
    someOtherMethod(); // works fine as the buffer address is pinned down in memory
}

在這種情況下,不安全版本將更好地工作。

雖然我無法明確權衡,但我可以分享自己的經歷。 我只使用了StringBuilder方法並且沒有遇到任何問題。 我喜歡它的簡單代碼和避免不安全。

這取決於編組的成本。 如果進行大量編組或編組的數據很大,則可能需要重復使用緩沖區,而不是每次都創建/銷毀字符串構建器緩沖區。

這取決於緩沖區中的數據實際上是什么。 如果是字符數據,請使用StringBuilder方法。 如果是二進制數據,則使用字節數組,但不要使用不安全方法。 雖然誇大的“不安全”的恐懼變得有點愚蠢,但沒有理由不在有保證的情況下使用它,在這種情況下它是沒有必要的。 采用:

//at class level...
[DllImport("mydll.dll")]
static extern int getNextResponse([In, Out] byte[] buffer);

//in main method body...
byte[] buffer = new byte[65536];
int rc = getNextResponse(buffer);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM