我是一个包装.NET项目里面的一些非托管C ++ code。为此,我需要系统::字符串
转换为存储在的char *
。
我不能确定这是否是最好的,甚至是正确的方法来做到这一点,我倒是AP preciate如果有人可以看看,并提供反馈。
谢谢
/大卫
//复制到空白的VisualStudio C ++ / CLR命令行的解决方案。
#包括stdafx.h中
#包括< stdio.h中>
使用命名空间系统;
使用命名空间系统::文本;
使用命名空间系统:运行:: InteropServices;
//测试要求使用char *参数。
无效MyTest的(为const char *缓冲区)
{
printf_s(%S \ N,缓冲区);
返回;
}
诠释的main()
{
//创建一个UTF-8编码。
UTF8Encoding ^ UTF8 = gcnew UTF8Encoding;
//一个统一$与外部8位code范围内的两个字符C $ C字符串。
字符串^ UNI codeSTRING = L这UNI code字符串包含两个字符codeS以外的8位code范围内,PI(\ u03a0)和Sigma(\ u03a3)。;
控制台:的WriteLine(UNI codeString的);
// EN code中的字符串。
阵列<字节> ^ EN codedBytes = utf8->的GetBytes(UNI codeString的);
//获取指向非托管字符数组
INT大小= ::元帅一下SizeOf(EN codedBytes [0])* EN codedBytes->长度;
IntPtr的PNT = ::元帅的AllocHGlobal(大小);
元帅::复制(EN codedBytes,0,PNT,EN codedBytes->长度);
//丑陋,但有必要吗?
字符* charPnt =(字符*)pnt.ToPointer();
MyTest的(charPnt);
元帅:FreeHGlobal(PNT);
}
解决方案
您并不需要创建一个连接codeR例如,你可以使用静态实例。
如果被调用的函数不指望一个指针HGLOBAL堆,你可以只使用普通的C / C ++内存分配(新的或的malloc)的缓冲区。
在您的例子中,函数没有取得所有权,所以你并不需要一个拷贝所有,只是引脚缓冲区。
是这样的:
// EN code中的文本作为UTF8
阵列<字节> ^ EN codedBytes =编码:: UTF8->的GetBytes(UNI codeString的);
// prevent GC四处移动字节,而这个变量是在栈上
pin_ptr<字节> pinnedBytes =安培; EN codedBytes [0];
//调用函数,从字节*强制转换 - >字符*是必需的
MyTest的(reinter pret_cast<字符*>(pinnedBytes),EN codedBytes->长度);
或者,如果你需要的字符串零结尾最喜欢的C函数(包括在OP的例子),那么你或许应该加上一个零字节。
// EN code中的文本为UTF8,确保数组是零结束
阵列<字节> ^ EN codedBytes =编码:: UTF8->的GetBytes(UNI $ C $的CString +\ 0);
// prevent GC四处移动字节,而这个变量是在栈上
pin_ptr<字节> pinnedBytes =安培; EN codedBytes [0];
//调用函数,从字节*强制转换 - >字符*是必需的
MyTest的(reinter pret_cast<字符*>(pinnedBytes));
I am wrapping some unmanaged C++ code inside a .NET project. For this I need to convert System::String
to UTF8-bytes stored in char*
.
I am unsure if this is the best or even a correct way to do this and I'd appreciate if someone could take a look and provide feedback.
Thanks,
/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);
}
解决方案
You don't need to create an encoder instance, you can use the static instances.
If the called function doesn't expect a pointer to the HGlobal heap you can just use plain C/C++ memory allocation (new or malloc) for the buffer.
In your example the function doesn't take ownership so you don't need a copy at all, just pin the buffer.
Something like:
// 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);
Or if you need the string zero-terminated like most C functions (including the example in the OP) then you should probably add a zero byte.
// 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));