2011-07-06 25 views
5

içinde depolanan UTF8 baytları için dize Bir .NET projesinde bazı yönetilmeyen C++ kodlarını kaydırıyorum. Bunun için System::String'u char*'da saklanan UTF8-byte dönüştürmem gerekiyor..NET System :: char *

Bunun için en doğru ya da doğru yol olup olmadığından emin değilim ve birileri bir göz atabilir ve geri bildirim sağlayabilirse memnun olurum.

sayesinde

/David

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

} 

cevap

11
  1. Sen statik örneğini kullanabilir, bir kodlayıcı örneğini oluşturmak gerekmez.

  2. Arayan işlev HGlobal yığınına bir işaretçi beklemiyorsa, arabellek için yalnızca düz C/C++ bellek ayırma (yeni veya malloc) kullanabilirsiniz.

  3. Örneğinizde bu işlev, sahiplik almaz, böylece bir kopyasına ihtiyacınız olmaz, yalnızca arabelleği sabitleyin. gibi

şey:

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

Yoksa dize (OP örneğin dahil) en C fonksiyonları gibi sıfır sonlandırılmış gerekirse sonra muhtemelen sıfır bayt eklemek gerekir.

// 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

Çok hoş, açıklama için teşekkürler. –

+1

Bu örnekte, pinnedBytes öğesinin üzerinde sıfır sonlandırıcıya nasıl ulaşacağını göremiyorum. Bunu garanti eden bir sihir var mı? Yoksa okuyucu için bir egzersiz olarak mı kaldı? – StilesCrisis

+1

@StilesCrisis oops, haklısınız, OP'nin onun char işaretçisini printf% s öğesine sıfırladığı ve bu sayının sıfırlanması gerektiği gerçeğini gözden kaçırmış olmalıyım. Pratikte sabitlenmiş baytlar genellikle sıfır bayt tarafından takip edilir, bu yüzden muhtemelen işe yaramazdı, ancak bunu garanti edecek herhangi bir kural bilmiyorum. Cevabı ben ayarlayacağım. – Zarat