C ++ / CLI System :: String ^ 'den std :: string' e dönüştürme


91

Birisi lütfen dönüştürecek basit bir kod gönderebilir mi?

System::String^

İçin,

C ++ std::string

Yani, sadece değerini atamak istiyorum,

String^ originalString;

İçin,

std::string newString;

Yanıtlar:


38

Kontrol edin System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()ve arkadaşları.

Maalesef şimdi kod gönderemiyorum; Göndermeden önce derlemesini kontrol etmek için bu makinede VS'ye sahip değilim.


162

Kendiniz yuvarlamayın, Microsoft tarafından sağlanan bu kullanışlı (ve genişletilebilir) sarmalayıcıları kullanın .

Örneğin:

#include <msclr\marshal_cppstd.h>

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

2
bu kullanışlı bağlantı için teşekkürler, bu ipucu beni çok fazla kodlamadan kurtardı. yan not olarak: şablonlar / sınıflar #include <msclr \ *. h> (ör. #include <msclr \ marshal.h>) ve msclr :: interop ad alanında, msdn.microsoft.com adresindeki bir örneğe bakın /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker

4
Bu uygun olsa da, uygun kodlama desteğinden tamamen yoksundur. SO soruma da bakın: stackoverflow.com/questions/18894551/… . Benim varsayımım, marshal_as'ın Unicode dizgelerini std :: string'deki ACP'ye dönüştürmesidir.
Mike Lischke

MS Önerisi, marshal_context kullanmak ve dönüştürme tamamlandıktan sonra onu silmektir. Bağlantı: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko

40

Bunu aşağıdaki gibi kolayca yapabilirsiniz

#include <msclr/marshal_cppstd.h>

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

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

Kısa ve basit bir çözüm ve basit bir çalışma örneği için +1 (kodunuzun sonunda fazladan bir parantez olmasına rağmen)
Simon Forsberg

Soruyu doğrudan cevaplayan tek çözüm budur.
Jiminion

8
hmm ... 33, neredeyse aynı kod satırlarıyla 2 yıldan fazla bir süre önce verilen bir cevaba olumlu oy verdi. bunun için çok puan kazanmaya saygı duyuyorum. ;-)
Beachwalker

20

Bu benim için çalıştı:

#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
İngilizce çeviri: "Bu gönderiye de yanıt vereceğim: s. Bu benim işlevim."
sivabudh

9

Burada bir c ++ / CLI proje için yıllar önce yazdığı bazı dönüşüm rutinleri onlar, gerektiği hala çalışır.

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, System :: Runtime :: InteropServices :: Marshal kullanın veya ad alanı kullanarak yazın System :: Runtime :: InteropServices; .
neo

6

Bir Windows form listbox ToString değerini standart bir dizeye dönüştürmeye çalışırken saatler harcadım, böylece bunu bir txt dosyasına çıktı olarak fstream ile birlikte kullanabilirdim. Visual Studio'm, birkaç yanıtın kullandığım söylediği sıralı başlık dosyalarıyla gelmedi. Bu kadar çok deneme ve yanılmadan sonra nihayet sadece System :: Runtime :: InteropServices kullanan soruna bir çözüm buldum:

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;

Ve işte örnek içeren MSDN sayfası: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Bunun oldukça basit bir çözüm olduğunu biliyorum, ancak bu bana HOURS sorun giderme ve sonunda işe yarayan bir şey bulmak için birkaç forum ziyaret ettim.


6

Bir String ^ den std :: string elde etmenin kolay bir yolu sprintf () kullanmaktır.

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

Marshal fonksiyonlarını çağırmanıza gerek yok!

GÜNCELLEME Eric sayesinde, arabellek taşmasını önlemek için girdi dizesinin boyutunu kontrol etmek için örnek kodu değiştirdim.


1
Yalnızca dizeleri sıralamak için özel olarak tasarlanmış işlevleri çağırmaktan kaçınmak için kodunuza bir arabellek taşması güvenlik açığı eklemek ilginç bir karardır.
Eric

Birisi mareşal işlevlerini kullanmak istemiyorsa farklı bir yaklaşım sunuyorum. Taşmayı önlemek için boyut için bir kontrol ekledim.
Ionian316

@Eric Dahili olarak sizin için sıralanıyor. Ayrıntılar için bu SO cevabına bakın. Önceden boyutu kontrol ederseniz, herhangi bir taşma sorunu yaşamazsınız ve kod çok daha temizdir.
Ionian316

4

C #, dizeleri için UTF16 biçimini kullanır.
Dolayısıyla, sadece türleri dönüştürmenin yanı sıra, dizenin gerçek biçimi konusunda da bilinçli olmalısınız.

Çok baytlı Karakter kümesi için derleme yaparken Visual Studio ve Win API UTF8'i varsayar (Aslında Windows-28591 olan Windows kodlaması ). Unicode Karakter seti
için derlerken Visual studio ve Win API UTF16 varsayar.

Bu nedenle, dizeyi UTF16'dan UTF8 biçimine dönüştürmelisiniz ve sadece std :: string'e dönüştürmemelisiniz.
Latin olmayan bazı diller gibi çok karakterli biçimlerle çalışırken bu gerekli hale gelecektir.

Fikir, std::wstring her zaman UTF16'yı temsil ettiğine karar vermektir .
Ve std::string her zaman UTF8'i temsil eder .

Bu derleyici tarafından uygulanmaz, sahip olunması daha iyi bir ilkedir.

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

Veya daha kompakt bir sözdiziminde bulundurun:

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
Kullanım durumumda UTF8'e dönüştürmenin önemini vurgulamak istiyorum: Win32 OpenFileDialog'dan alınan bir dosya yolunu (çok baytlı karakterlere sahip dosya adlarının mümkün olduğu, örneğin Asya karakterlerini içeren dosya adları gibi) std aracılığıyla motor koduna geçirmem gerekiyordu. :: string, bu nedenle UTF8'e dönüştürme hayati önem taşıyordu. Mükemmel cevap için teşekkürler!
Jason McClinsey

0

Şeriften uzak durmayı seviyorum.

Using CString newString(originalString);

Bana çok daha temiz ve daha hızlı görünüyor. Bir bağlam oluşturmak ve silmek konusunda endişelenmenize gerek yok.


0

// Aşağıdaki kodu yazmak için VS2012'yi kullandım-- convert_system_string'i Standard_Sting'e çevirin

        #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;
        }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.