【问题标题】:How to convert C++/CLI string to const char*如何将 C++/CLI 字符串转换为 const char*
【发布时间】:2016-04-20 10:49:00
【问题描述】:

我有一个 C++/CLI DLL,我计划将其用作我的 C# DLL 和本机 C++ 客户端之间的适配器。我需要在两个方向上传递字符串。该适配器使用 VS2013 编译,但需要支持使用 VS2008 构建的客户端,因此我在 API 中使用 const char*。但是,即使两者都是 VS2013 构建的,我所拥有的也无法正常工作。

在其他地方,我找到了使用 msclr\marshal.h 的建议,因此我创建了:

using namespace msclr::interop;
System::String^ ToCliString(const char* s)
{
    System::String ^result = marshal_as<System::String^>(s);
    return result;
}    
const char* ToCppString(System::String^ s)
{
    msclr::interop::marshal_context context;
    const char* result = context.marshal_as<const char*>(s);
    return result;
}

为了测试这些,我在我的 C++/CLI DLL 中创建了一个往返转换方法:

const char* Foo(const char *cstar)
{
    System::String^ cli = ::ToCliString(cstar);

    if (cli == "abc")
    {
        MessageBox::Show("const char* -> CLI: OK");
    }

    const char* cstar2 = ::ToCppString(cli);

    if (std::strcmp(cstar2, "abc") == 0)
    {
        MessageBox::Show("CLI -> const char*: OK");
    }
    else if (std::strcmp(cstar2, "") == 0)
    {
        MessageBox::Show("ToCppString returned empty string");
    }
    else
    {
        MessageBox::Show("ToCppString returned something else");
    }

    return cstar2;
}

当本地 C++ 客户端调用 Foo("abc") 时,会显示第一条消息,然后显示“返回其他内容”消息,并且客户端会收到垃圾邮件 (îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþÞ›vÚ§)。所以看起来我的第二次转换不起作用。

更新

这是我使用的最终解决方案。

我使用 zneaks 的建议来编组到 std::string 和 PaulMcKenzie 的建议来传递调用者分配的 char* 而不是返回 const char*。谢谢两位。

void ToCppString(System::String^ input, char* output)
{
    std::string temp= marshal_as<std::string>(input);
    strcpy(output, temp.c_str());
}

void Foo(const char* input, char* output)
{
    System::String^ cli = ::ToCliString(input);
    ::ToCppString(cli, output);
}

【问题讨论】:

  • 您正在返回一个指向局部变量 cstar2 的指针,这是未定义的行为。
  • @PaulMcKenzie 因此,要将字符串从 C# 传递到本机 C++ 客户端,客户端需要传递适配器“填充”的 char *?
  • 这是通常的做法。客户端提供缓冲区,C++ 代码用数据填充缓冲区。
  • @PaulMcKenzie 那么客户端是否需要调用 delete 来防止内存泄漏?我猜他们可以分配一次缓冲区,在我的 API 中调用许多函数,并在完成后删除。所以我的 API 应该包含另一个参数,以便他们可以告诉我可以返回的最大大小消息?或者更适合让属性客户端可以查询以确定我的最大消息长度?
  • 客户端负责正确维护缓冲区。它可能已分配有new[] / delete[],甚至可能是std::vector&lt;char&gt;,而您正在传递std::vector&lt;char&gt;::data(),等等。

标签: c# c++ c dll


【解决方案1】:

问题是marshal_context拥有你得到的char指针,所以它是deallocated when your function returns

本示例创建了一个上下文,用于从 System::Stringconst char * 变量类型的封送处理。转换后的数据在删除的行之后将无效上下文。

考虑改用marshal_as&lt;std::string&gt;,因为允许字符串比marshal_context 寿命更长。

【讨论】:

  • 我刚刚尝试用 std::string result = context.marshal_as<:string>(s); 替换 ToCppString 的最后两行返回结果.c_str();但同样的结果。我想知道,由于本地 std::string 超出范围,其 c_str() 函数返回的值是否仍然有效?
  • 知道了,现在将 strcpy 用于新参数。很快就会发布我的解决方案。
  • @JimC,是的,c_str() 返回的指针归字符串所有,并在函数返回时被释放,所以你基本上又遇到了同样的问题。不过,您可以返回 std::string
  • 我可以,但这只是在踢罐子,因为我无法将 std::string 一直返回到应用程序(我必须支持使用不同版本的 Visual Studio 构建的应用程序。 )
  • 然后小心自己删除字符串。
【解决方案2】:

另外,请注意 VC++ 2008 express 不包含 marshal 头文件(marshal.h 等),因此您必须使用 VC++ 2008 pro 或更高版本。看起来这些头文件自 VS2010 起包含在 Express Edition 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    • 2015-12-19
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    相关资源
    最近更新 更多