2011-07-06 14 views
5

Estoy envolviendo un código C++ no administrado dentro de un proyecto .NET. Para esto necesito convertir System::String a UTF8-bytes almacenado en char*..NET System :: Cadena a UTF8-bytes almacenada en char *

No estoy seguro de si esta es la mejor o incluso la forma correcta de hacerlo y agradecería que alguien pudiera echar un vistazo y dar su opinión.

Gracias,

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

} 

Respuesta

11
  1. No es necesario crear una instancia del codificador, puede utilizar las instancias estáticas.

  2. Si la función llamada no espera un puntero al almacenamiento dinámico de HGlobal, puede utilizar la asignación de memoria simple C/C++ (nueva o malloc) para el almacenamiento intermedio.

  3. En su ejemplo, la función no se apropia, por lo que no necesita una copia, simplemente fije el búfer.

Algo así como:

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

O si usted necesita la cadena terminada en cero como la mayoría de las funciones C (incluyendo el ejemplo de la OP), entonces probablemente debería añadir un byte cero.

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

Muy bien, gracias por la explicación. –

+1

En este ejemplo, no veo cómo 'pinnedBytes' obtendrá un terminador cero en él. ¿Hay algo de magia que lo garantice? ¿O es eso dejado como un ejercicio para el lector? – StilesCrisis

+1

@StilesCrisis Vaya, tiene razón, debo haber pasado por alto el hecho de que el OP pasaba su puntero a printf% s, que lo necesita terminar en cero. En la práctica, los bytes anclados suelen ir seguidos de cero bytes, por lo que probablemente funcione de todos modos, pero no conozco ninguna regla que lo garantice. Ajustaré la respuesta. – Zarat

Cuestiones relacionadas