C++ .NET 将 System::String 转换为 std::string

Posted

技术标签:

【中文标题】C++ .NET 将 System::String 转换为 std::string【英文标题】:C++ .NET convert System::String to std::string 【发布时间】:2009-08-19 15:28:56 【问题描述】:

如何在 C++ .NET 中将 System::String 转换为 std::string?

【问题讨论】:

不要。转换为 std::wstring。 System.String 是 Unicode,而不是 ASCII @MSalters 嗯?您似乎认为转换不包括翻译,或者每个人都可以随时选择他们要与之交互的 API... 或者std::string必须是ASCII(提示:它应该是UTF-8!) 【参考方案1】:

如果您使用的是最新版本的 .net,语法会更简洁

#include "stdafx.h"
#include <string>

#include <msclr\marshal_cppstd.h>

using namespace System;

int main(array<System::String ^> ^args)

    System::String^ managedString = "test";

    msclr::interop::marshal_context context;
    std::string standardString = context.marshal_as<std::string>(managedString);

    return 0;

这还可以让您在面对异常时进行更好的清理。

还有一个msdn article 用于各种其他转换

【讨论】:

这是否也处理从 UTF-16(.Net 默认)到 UTF-8(std::string)的编码? @zak,在内部,msclr::interop::marshal_context 中的代码使用 Win32 API WideCharToMultiByte,它最终会转换为 Windows-1252 编码,至少在我的经验中是这样。可能有办法解决它,我不确定,但我认为如果你想要 UTF-8,你需要自己做。例如,英镑符号 '£' 被转换为单字节 0xA3,而拉丁字母 Q 'ʠ' 被转换为单个 '?'。无论 C++/CLI 项目(MBCS 或 Unicode)的字符集项目设​​置如何,它都会以这种方式运行。 我们什么时候在#include标签中使用反斜杠(\)?【参考方案2】:

为了响应更高版本的 C++/CLI 中的“更简单的方式”,您可以在没有 marshal_context 的情况下执行此操作。我知道这适用于 Visual Studio 2010;在此之前不确定。


#include "stdafx.h"
#include <string>

#include <msclr\marshal_cppstd.h>

using namespace msclr::interop;

int main(array<System::String ^> ^args)

    System::String^ managedString = "test";

    std::string standardString = marshal_as<std::string>(managedString);

    return 0;


【讨论】:

查看链接到的 MSDN 文章 Collin 以了解何时使用 marshal_as 以及何时使用 marshal_context。一般来说,当需要清理非托管资源时,需要 marshal_context。 文章说,如果本机类型没有析构函数来进行自己的清理,则只需要上下文。那么,对于std::string,是否需要这样做? std::string 不需要上下文。仅当从包装类型封送到未包装类型(即原始指针)时才需要上下文。如Overview of Marshaling in C++ 中所列,只有三个实例需要上下文。 感谢@Mike Johnson,...在此之前我正要离开 C++。现在再次继续......呵呵:D 我尝试使用它,但遇到了它不起作用的问题,因为我的 System::String^ 是一个类变量。所以我不得不复制构造一个新的 String^ 并将其传递给 marshal_as。我讨厌 Visual Studio。【参考方案3】:

C# 对其字符串使用 UTF16 格式。 因此,除了转换类型之外,您还应该注意字符串的实际格式。

当为多字节字符集编译时,Visual Studio 和 Win API 假定为 UTF8(实际上 windows 编码是 Windows-28591)。 为 Unicode 字符集编译时,Visual Studio 和 Win API 假定为 UTF16。

因此,您还必须将字符串从 UTF16 转换为 UTF8 格式,而不仅仅是转换为 std::string。 这在处理多字符格式(如某些非拉丁语言)时将变得很有必要。

这个想法是确定std::wstring always 代表 UTF16。 而std::string always 代表 UTF8

这不是由编译器强制执行的,它更像是一个好的策略。

#include "stdafx.h"
#include <string>

#include <msclr\marshal_cppstd.h>

using namespace System;

int main(array<System::String ^> ^args)

    System::String^ managedString = "test";

    msclr::interop::marshal_context context;

    //Actual format is UTF16, so represent as wstring
    std::wstring utf16NativeString = context.marshal_as<std::wstring>(managedString); 

    //C++11 format converter
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    //convert to UTF8 and std::string
    std::string utf8NativeString = convert.to_bytes(utf16NativeString);

    return 0;

或者使用更紧凑的语法:

int main(array<System::String ^> ^args)

    System::String^ managedString = "test";

    msclr::interop::marshal_context context;
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    std::string utf8NativeString = convert.to_bytes(context.marshal_as<std::wstring>(managedString));

    return 0;

【讨论】:

Win API 采用 UTF8(实际上是 Windows 编码,即 Windows-28591) -> afaik 窄字符串 API 版本采用系统代码页,它可以是很多东西,但绝不是 UTF -8.【参考方案4】:
stdString = toss(systemString);

  static std::string toss( System::String ^ s )
  
    // convert .NET System::String to std::string
    const char* cstr = (const char*) (Marshal::StringToHGlobalAnsi(s)).ToPointer();
    std::string sstr = cstr;
    Marshal::FreeHGlobal(System::IntPtr((void*)cstr));
    return sstr;
  

【讨论】:

这是较旧的语法。我更喜欢 Colin 上面建议的那个。 如果 sstr() 抛出怎么办?这不会导致 cstr 成为泄漏吗?【参考方案5】:

上面的答案出现了太多模棱两可的错误(是的,我是 C++ 菜鸟)

这对我有用,可以将字符串从 C# 发送到 C++ CLI

C#

bool result;
result = mps.Import(mpsToolName);

C++ CLI

功能:

bool ManagedMPS::Import(System::String^ mpsToolNameTest)
std::string mpsToolName;
mpsToolName = toStandardString(mpsToolNameTest);

将 String^ 转换为 std::string 的函数

static std::string toStandardString(System::String^ string)

 using System::Runtime::InteropServices::Marshal;
 System::IntPtr pointer = Marshal::StringToHGlobalAnsi(string);
 char* charPointer = reinterpret_cast<char*>(pointer.ToPointer());
 std::string returnString(charPointer, string->Length);
 Marshal::FreeHGlobal(pointer);
 return returnString;

经过进一步研究,这似乎更清洁、更安全。

我改用这种方法了。

std::string Utils::ToUnmanagedString(String^ stringIncoming)

   std::string unmanagedString = marshal_as<std::string>(stringIncoming);
   return unmanagedString;

【讨论】:

那么您是如何设法摆脱所有 IServiceProvider 歧义错误的? 我不记得有这些错误。我是 C++ 新手,现在我正在与不同公司签订另一个合同/项目.... 祝你好运。【参考方案6】:

创建一个可以使用的 Windows 运行时组件:

String^ systemString = "Hello";
std::wstring ws1(systemString ->Data());
std::string standardString(ws1.begin(), ws1.end());

【讨论】:

以上是关于C++ .NET 将 System::String 转换为 std::string的主要内容,如果未能解决你的问题,请参考以下文章

将 System::String^ (C# 字符串)转换为 C++ std::string [重复]

c# string与c++ std::string的互相转换

c# string与c++ std::string的互相转换

托管C++中System::String^ 转换为 char*

无法将类型“System.String”的对象转换为类型“System.Byte []”错误 MYSQL NET CORE 3.1

无法将对象类型“System.String[*]”转换为“System.String[]”