C ++ / CLI Konwersja z System :: String ^ do std :: string


91

Czy ktoś może opublikować prosty kod, który umożliwi konwersję,

System::String^

Do,

C ++ std::string

To znaczy, chcę tylko przypisać wartość,

String^ originalString;

Do,

std::string newString;

Odpowiedzi:


39

Sprawdź System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()i jego przyjaciół.

Przepraszamy, nie mogę teraz wysłać kodu; Nie mam programu VS na tym komputerze, aby sprawdzić, czy się kompiluje przed wysłaniem.


164

Nie twórz własnego, użyj tych przydatnych (i rozszerzalnych) opakowań dostarczonych przez firmę Microsoft.

Na przykład:

#include <msclr\marshal_cppstd.h>

System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);

2
dzięki za ten przydatny link, ta wskazówka zaoszczędziła mi dużo czasu na kodowaniu. na marginesie: szablony / klasy znajdują się w #include <msclr \ *. h> (np. #include <msclr \ marshal.h>) oraz w przestrzeni nazw msclr :: interop, zobacz przykład na msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
— Beachwalker

4
Chociaż jest to wygodne, całkowicie brakuje odpowiedniej obsługi kodowania. Zobacz także moje pytanie dotyczące SO: stackoverflow.com/questions/18894551/… . Moje założenie jest takie, że marshal_as konwertuje ciągi Unicode na ACP w std :: string.
— Mike Lischke

Rekomendacją MS jest użycie marshal_context i usunięcie go po zakończeniu konwersji. Link: msdn.microsoft.com/en-us/library/bb384856.aspx
— Ruslan Makrenko

40

Możesz to łatwo zrobić w następujący sposób

#include <msclr/marshal_cppstd.h>

System::String^ xyz="Hi boys"; 

std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);

+1 dla krótkiego i prostego rozwiązania oraz prostego przykładu działania (chociaż na końcu twojego kodu jest dodatkowy nawias)
— Simon Forsberg

To jedyne rozwiązanie, które bezpośrednio odpowiada na to pytanie.
— Jiminion

8
hmm ... 33 głosy za odpowiedzią, która została udzielona już ponad 2 lata wcześniej z prawie tymi samymi liniami kodu. szacunek dla zdobycia za to tylu punktów. ;-)
— Beachwalker

20

To zadziałało dla mnie:

#include <stdlib.h>
#include <string.h>
#include <msclr\marshal_cppstd.h>
//..
using namespace msclr::interop;
//..
System::String^ clrString = (TextoDeBoton);
std::string stdString = marshal_as<std::string>(clrString); //String^ to std
//System::String^ myString = marshal_as<System::String^>(MyBasicStirng); //std to String^
prueba.CopyInfo(stdString); //MyMethod
//..
//Where: String^ = TextoDeBoton;
//and stdString is a "normal" string;

3
Tłumaczenie angielskie: „Odpowiem również na ten post: p. To jest moja funkcja”.
— sivabudh

9

Oto kilka procedur konwersji, które napisałem wiele lat temu dla projektu c ++ / cli, powinny nadal działać.

void StringToStlWString ( System::String const^ s, std::wstring& os)
    {
        String^ string = const_cast<String^>(s);
        const wchar_t* chars = reinterpret_cast<const wchar_t*>((Marshal::StringToHGlobalUni(string)).ToPointer());
        os = chars;
        Marshal::FreeHGlobal(IntPtr((void*)chars));

    }
    System::String^ StlWStringToString (std::wstring const& os) {
        String^ str = gcnew String(os.c_str());
        //String^ str = gcnew String("");
        return str;
    }

    System::String^ WPtrToString(wchar_t const* pData, int length) {
        if (length == 0) {
            //use null termination
            length = wcslen(pData);
            if (length == 0) {
                System::String^ ret = "";
                return ret;
            }
        }

        System::IntPtr bfr = System::IntPtr(const_cast<wchar_t*>(pData));
        System::String^ ret = System::Runtime::InteropServices::Marshal::PtrToStringUni(bfr, length);
        return ret;
    }

    void Utf8ToStlWString(char const* pUtfString, std::wstring& stlString) {
        //wchar_t* pString;
        MAKE_WIDEPTR_FROMUTF8(pString, pUtfString);
        stlString = pString;
    }

    void Utf8ToStlWStringN(char const* pUtfString, std::wstring& stlString, ULONG length) {
        //wchar_t* pString;
        MAKE_WIDEPTR_FROMUTF8N(pString, pUtfString, length);
        stlString = pString;
    }

@alap, Use System :: Runtime :: InteropServices :: Marshal lub pisz używając przestrzeni nazw System :: Runtime :: InteropServices; .
— neo

6

Spędziłem wiele godzin próbując przekonwertować wartość ToString formularza listbox systemu Windows na standardowy ciąg, aby móc go użyć z fstream do wyjścia do pliku txt. Mój program Visual Studio nie zawierał plików nagłówkowych Marshal, których używam w kilku odpowiedziach. Po tylu próbach i błędach w końcu znalazłem rozwiązanie problemu, które używa tylko System :: Runtime :: InteropServices:

void MarshalString ( String ^ s, string& os ) {
   using namespace Runtime::InteropServices;
   const char* chars = 
      (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
   os = chars;
   Marshal::FreeHGlobal(IntPtr((void*)chars));
}

//this is the code to use the function:
scheduleBox->SetSelected(0,true);
string a = "test";
String ^ c = gcnew String(scheduleBox->SelectedItem->ToString());
MarshalString(c, a);
filestream << a;

A oto strona MSDN z przykładem: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Wiem, że to całkiem proste rozwiązanie, ale zajęło mi to GODZINY rozwiązywania problemów i odwiedzenia kilku forów, aby w końcu znaleźć coś, co działało.


6

Znalazłem prostym sposobem na uzyskanie std :: string z String ^ jest użycie sprintf ().

char cStr[50] = { 0 };
String^ clrString = "Hello";
if (clrString->Length < sizeof(cStr))
  sprintf(cStr, "%s", clrString);
std::string stlString(cStr);

Nie ma potrzeby wywoływania funkcji Marshal!

AKTUALIZACJA Dzięki Ericowi zmodyfikowałem przykładowy kod, aby sprawdzić rozmiar ciągu wejściowego, aby zapobiec przepełnieniu bufora.


1
To ciekawa decyzja o wprowadzeniu w kodzie luki przepełnienia bufora tylko po to, aby uniknąć wywoływania funkcji specjalnie zaprojektowanych do kierowania ciągami.
— Eric

Po prostu przedstawiam inne podejście, jeśli ktoś nie chce używać funkcji marszałka. Dodałem sprawdzenie rozmiaru, aby zapobiec przepełnieniu.
— Ionian316,

@Eric Wewnętrznie to krosowanie dla Ciebie. Zobacz tę odpowiedź SO, aby uzyskać szczegółowe informacje. Jeśli wcześniej sprawdzisz rozmiar, nie będziesz mieć żadnych problemów z przepełnieniem, a kod jest znacznie czystszy.
— Ionian316

4

C # używa formatu UTF16 dla swoich ciągów.
Tak więc, oprócz zwykłej konwersji typów, powinieneś być również świadomy faktycznego formatu ciągu.

Podczas kompilowania dla zestawu znaków wielobajtowych program Visual Studio i interfejs API Win zakłada UTF8 (w rzeczywistości kodowanie systemu Windows, czyli Windows-28591 ).
Podczas kompilowania zestawu znaków Unicode Visual studio i interfejs API Win zakładają UTF16.

Dlatego też musisz przekonwertować łańcuch z formatu UTF16 na UTF8, a nie tylko przekonwertować go na std :: string.
Będzie to konieczne podczas pracy z formatami wieloznakowymi, takimi jak niektóre języki inne niż łacińskie.

Chodzi o to, aby zdecydować, że std::wstring zawsze reprezentuje UTF16 .
I std::string zawsze reprezentuje UTF8 .

Nie jest to wymuszane przez kompilator, jest to raczej dobra polityka.

#include "stdafx.h"
#include <string>
#include <codecvt>
#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;
}

Lub utwórz bardziej zwartą składnię:

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;
}

1
Chcę tylko podkreślić znaczenie konwersji do UTF8 w moim przypadku użycia: potrzebowałem przekazać ścieżkę do pliku otrzymaną z Win32 OpenFileDialog (gdzie możliwe są nazwy plików ze znakami wielobajtowymi, np. Nazwy plików zawierające znaki azjatyckie) do kodu silnika przez std :: string, więc konwersja do UTF8 była niezbędna. Dzięki za doskonałą odpowiedź!
— Jason McClinsey,

0

Lubię trzymać się z dala od marszałka.

Using CString newString(originalString);

Wydaje mi się dużo czystszy i szybszy. Nie musisz się martwić o tworzenie i usuwanie kontekstu.


0

// Użyłem VS2012 do napisania poniższego kodu - convert_system_string do Standard_Sting

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

        using namespace System;
        using namespace Runtime::InteropServices; 


        void MarshalString ( String^ s, std::string& outputstring )
        {  
           const char* kPtoC =  (const char*) (Marshal::StringToHGlobalAnsi(s)).ToPointer();                                                        
           outputstring = kPtoC;  
           Marshal::FreeHGlobal(IntPtr((void*)kPtoC));  
        }   

        int _tmain(int argc, _TCHAR* argv[])
        {
             std::string strNativeString;  
             String ^ strManagedString = "Temp";

             MarshalString(strManagedString, strNativeString);  
             std::cout << strNativeString << std::endl; 

             return 0;
        }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.