2011-07-06 139 views
5

我在.NET項目中包裝了一些非託管C++代碼。爲此,我需要將System::String轉換爲存儲在char*中的UTF8字節。.NET系統::字符串到UTF8字節存儲在字符*

我不確定這是否是最好的,甚至是正確的方法來做到這一點,我會很感激,如果有人可以看看並提供反饋意見。

感謝,

/大衛

// Copy into blank VisualStudio C++/CLR command line solution. 
#include "stdafx.h" 
#include <stdio.h> 

using namespace System; 
using namespace System::Text; 
using namespace System::Runtime::InteropServices; 

// Test for calling with char* argument. 
void MyTest(const char* buffer) 
{ 
    printf_s("%s\n", buffer); 
    return; 
} 

int main() 
{ 

    // Create a UTF-8 encoding. 
    UTF8Encoding^ utf8 = gcnew UTF8Encoding; 

    // A Unicode string with two characters outside an 8-bit code range. 
    String^ unicodeString = L"This unicode string contains two characters with codes outside an 8-bit code range, Pi (\u03a0) and Sigma (\u03a3)."; 
    Console::WriteLine(unicodeString); 

    // Encode the string. 
    array<Byte>^encodedBytes = utf8->GetBytes(unicodeString); 

    // Get pointer to unmanaged char array 
    int size = Marshal::SizeOf(encodedBytes[0]) * encodedBytes->Length; 
    IntPtr pnt = Marshal::AllocHGlobal(size); 
    Marshal::Copy(encodedBytes, 0, pnt, encodedBytes->Length); 

    // Ugly, but necessary? 
    char *charPnt= (char *)pnt.ToPointer(); 
    MyTest(charPnt); 
    Marshal::FreeHGlobal(pnt); 

} 

回答

11
  1. 你並不需要創建一個編碼器實例,您可以使用靜態實例。

  2. 如果被調用的函數不期望指向HGlobal堆的指針,那麼您可以爲緩衝區使用純C/C++內存分配(new或malloc)。

  3. 在你的例子中,函數並不擁有所有權,所以你根本不需要拷貝,只需要將緩衝區放在一邊即可。

喜歡的東西:

// Encode the text as UTF8 
array<Byte>^ encodedBytes = Encoding::UTF8->GetBytes(unicodeString); 

// prevent GC moving the bytes around while this variable is on the stack 
pin_ptr<Byte> pinnedBytes = &encodedBytes[0]; 

// Call the function, typecast from byte* -> char* is required 
MyTest(reinterpret_cast<char*>(pinnedBytes), encodedBytes->Length); 

或者,如果你需要的字符串零結尾最喜歡的C函數(包括在OP的例子),那麼你或許應該加上一個零字節。

// Encode the text as UTF8, making sure the array is zero terminated 
array<Byte>^ encodedBytes = Encoding::UTF8->GetBytes(unicodeString + "\0"); 

// prevent GC moving the bytes around while this variable is on the stack 
pin_ptr<Byte> pinnedBytes = &encodedBytes[0]; 

// Call the function, typecast from byte* -> char* is required 
MyTest(reinterpret_cast<char*>(pinnedBytes)); 
+0

非常好,謝謝你的解釋。 –

+1

在這個例子中,我看不到'pinnedBytes'如何得到一個零終止符。有沒有保證這一點的魔法?還是作爲讀者的練習呢? – StilesCrisis

+1

@StilesCrisis oops,你是對的,我一定忽略了這樣一個事實,即OP正在將他的字符指針傳給printf%s,它需要零終止。實際上,固定字節通常後跟零字節,所以它可能會起作用,但我不知道任何可以保證的規則。我會調整答案。 – Zarat