在C++/CLI中,将char*和System::String相互转换的最佳方式是什么?

49
什么是在C++/CLI中从char*转换为System::string的批准方式,然后再转回去的方法?我在Google上找到了一些关于marshal_to<>模板函数的参考资料,但似乎这个功能从未纳入Visual Studio 2005(据我所知,它也不在Visual Studio 2008中)。我还看到过Stan Lippman的博客中的一些代码,但那是2004年的。我还看到了Marshal::StringToHGlobalAnsi()。是否有一种被认为是“最佳实践”的方法?
5个回答

80

System::String有一个接受char*类型参数的构造函数:

 using namespace system;
 const char* charstr = "Hello, world!";
 String^ clistr = gcnew String(charstr);
 Console::WriteLine(clistr);

获得一个char*指针需要一些技巧,但并不难:

 IntPtr p = Marshal::StringToHGlobalAnsi(clistr);
 char *pNewCharStr = static_cast<char*>(p.ToPointer());
 cout << pNewCharStr << endl;
 Marshal::FreeHGlobal(p);

5
+1,System::String构造函数还接受长度和编码参数! - Anthony Serdyukov
6
marshal_context相比,Marshal::StringToHGlobalAnsi是一个较差的选择(正如Matthew所提到的),因为它没有使用RAII自动释放缓冲区。更不用说这个名字完全错误,它根本不返回HGLOBAL - Ben Voigt
你的示例在我使用.NET 4.6.1的C++/CLI中无法工作。没有System::String构造函数可以接受char,只有signed char或wchar_t*。 - Dewey Vozel
我已经有一段时间没有进入这个领域了,但我相信这仍然可以工作。根据 https://learn.microsoft.com/en-us/cpp/windows/string-cpp-component-extensions 上的文档,您仍然可以使用char *字符串作为参数来gcnew一个字符串。也许您可以转换为signed char * - Ben Straub
根据我的经验,指针也没有空终止符。您需要使用 clistr.Length 来了解它的长度。 - Menace

18

7
谢谢,但那是一个冗长的解释。这更加直接:#include <msclr\marshal.h> // marshal_context context; // my_c_string = context.marshal_as<const char*>(my_csharp_string); - gatopeich
对于那些想知道的人,context 的完整命名空间是 msclr::interop::marshal_context - Mugen

0

我创建了一些辅助方法。我需要这样做是为了从旧的Qt库转移到CLI String。如果有人能够补充并告诉我是否似乎存在内存泄漏以及我可以采取什么措施来解决它,我将不胜感激。

void MarshalString (  String ^ s, wstring& os ) {
    using namespace Runtime::InteropServices;
    const wchar_t* char = (const wchar_t*)(Marshal::StringToHGlobalUni(s)).ToPointer();
    os = char;
}
QString SystemStringToQt( System::String^ str)
{
    wstring t;
    MarshalString(str, t);
    QString r = QString::fromUcs2((const ushort*)t.c_str());
    return r;
}

可能需要使用Marshal::FreeHGlobal(IntPtr((void*)chars));来释放它。 - Patrick.SE
1
@Pat 是的,抱歉我应该在这之后更新一下。现在我已经成功地让它运行良好了。将其移植到 .NET 后,这个应用程序的性能提高了 3 倍,即使是在处理 marshaling 的时候也是如此。 - dko

0
我们所做的是创建了一个C++\CLI对象,该对象在未管理的代码中保存字符串,并提供托管副本。转换代码看起来非常像Stan博客上的代码(我无法完全记住它)(如果您使用他的代码,请确保更新为使用delete[]),但我们确保析构函数将处理释放对象的所有未管理元素。这有点过度,但当我们连接到旧的C++代码模块时,我们没有泄漏问题。

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接