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