How do you convert System::String to std::string in C++ .NET?
-
5Don't. Convert to std::wstring. System.String is Unicode, not ASCII – MSalters Aug 20 '09 at 07:54
-
6@MSalters Huh? You seem to be under the impression that conversion doesn't include translation or that everyone can always choose what API's they're going to interact with... – Mar 18 '13 at 18:21
-
Or that `std::string` _must_ be ASCII (hint: it _should_ be UTF-8!) – Lightness Races in Orbit Nov 20 '19 at 14:24
6 Answers
There is cleaner syntax if you're using a recent version of .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;
}
This also gives you better clean-up in the face of exceptions.
There is an msdn article for various other conversions

- 4,234
- 1
- 21
- 16
-
Does this also take care of encoding from UTF-16 (.Net default) to UTF-8 (std::string)? – zak Mar 06 '18 at 10:12
-
@zak, internally the code in `msclr::interop::marshal_context` uses the Win32 API `WideCharToMultiByte` which ultimately converts to Windows-1252 encoding, at least in my experience. There may be ways around it, I am not sure, but I think you'll need to do it yourself if you want UTF-8. For example, the British Pound sign, '£', is converted to the single-byte 0xA3, while the Latin Letter Q, 'ʠ', is converted to a single '?'. It behaves this way regardless of the Character Set project setting of the C++/CLI project (MBCS or Unicode). – Mike E Aug 14 '18 at 17:56
-
And in response to the "easier way" in later versions of C++/CLI, you can do it without the marshal_context. I know this works in Visual Studio 2010; not sure about prior to that.
#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;
}

- 361
- 4
- 6
-
1Look at the MSDN article Collin linked to to see when to use marshal_as and when to use the marshal_context. Generally speaking the marshal_context is needed when unmanaged resources need to cleaned up. – rotti2 Apr 29 '10 at 10:28
-
3The article says one only needs a context if the native type does not have a destructor to do its own cleanup. So, in the case of `std::string`, is this needed? – Kristopher Johnson May 04 '11 at 17:39
-
2The context is not needed for `std::string`. Context is only needed when marshaling from a wrapped type to an unwrapped type (i.e. raw pointer). As listed in [Overview of Marshaling in C++](http://msdn.microsoft.com/en-us/library/bb384865.aspx), there are only three instances where the context is needed. – Edward Brey Jan 11 '13 at 12:45
-
thanks for this @Mike Johnson,... i was about to leave C++ before this. And now continue again... hehe :D – gumuruh May 05 '16 at 10:17
-
1I tried to use this, and ran into the issue where it wouldn't work because my System::String^ was a class variable. So I had to copy construct a new String^ and pass that to marshal_as. I hate Visual Studio. – PfunnyGuy Apr 11 '17 at 21:35
-
C# uses the UTF16 format for its strings.
So, besides just converting the types, you should also be conscious about the string's actual format.
When compiling for Multi-byte Character set Visual Studio and the Win API assumes UTF8 (Actually windows encoding which is Windows-28591 ).
When compiling for Unicode Character set Visual studio and the Win API assume UTF16.
So, you must convert the string from UTF16 to UTF8 format as well, and not just convert to std::string.
This will become necessary when working with multi-character formats like some non-latin languages.
The idea is to decide that std::wstring
always represents UTF16.
And std::string
always represents UTF8.
This isn't enforced by the compiler, it's more of a good policy to have.
#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;
}
Or have it in a more compact syntax:
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;
}

- 48,127
- 24
- 147
- 185
-
_Win API assumes UTF8 (Actually windows encoding which is Windows-28591 )_ -> afaik narrow string API versions assume the system code page, which can be many things but never UTF-8. – heinrichj May 07 '18 at 07:45
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;
}

- 34,865
- 12
- 85
- 147
I had too many ambiguous errors showing up with the above answers ( yes, i'm a C++ noob)
This worked for me for sending string from C# to C++ CLI
C#
bool result;
result = mps.Import(mpsToolName);
C++ CLI
function:
bool ManagedMPS::Import(System::String^ mpsToolNameTest)
std::string mpsToolName;
mpsToolName = toStandardString(mpsToolNameTest);
function that works from converting String^ to 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;
}
ON FURTHER RESEARCH, it appears that this is cleaner and safer.
I switched to using this method instead.
std::string Utils::ToUnmanagedString(String^ stringIncoming)
{
std::string unmanagedString = marshal_as<std::string>(stringIncoming);
return unmanagedString;
}

- 19,633
- 6
- 111
- 113
-
1So how did you manage to get rid of all the IServiceProvider ambiguity errors? – Arman Bimatov Aug 17 '13 at 18:21
-
I don't recall getting those errors. I was new to C++ , now I'm on another contract/project with different company.... sorry best of luck. – Tom Stickel Aug 17 '13 at 19:20
Creating a Windows Runtime Component you can use:
String^ systemString = "Hello";
std::wstring ws1(systemString ->Data());
std::string standardString(ws1.begin(), ws1.end());

- 1,305
- 2
- 15
- 33