C ++ / CLI แปลงจาก System :: String ^ เป็น std :: string


94

ใครช่วยโพสต์รหัสง่ายๆที่จะแปลง

System::String^

ถึง,

C ++ std::string

คือฉันแค่ต้องการกำหนดค่าของ

String^ originalString;

ถึง,

std::string newString;

คำตอบ:


39

เช็คเอาท์ System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()และเพื่อน ๆ

ขออภัยไม่สามารถโพสต์รหัสได้ในขณะนี้ ฉันไม่มี VS ในเครื่องนี้เพื่อตรวจสอบคอมไพล์ก่อนโพสต์


166

อย่าม้วนของคุณเองใช้สิ่งเหล่านี้มีประโยชน์ (และขยาย) ห่อให้โดยไมโครซอฟท์

ตัวอย่างเช่น:

#include <msclr\marshal_cppstd.h>

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

2
ขอบคุณสำหรับลิงค์ที่มีประโยชน์คำใบ้นี้ช่วยฉันในการเข้ารหัสได้มาก เป็นหมายเหตุด้านข้าง: เทมเพลต / คลาสอยู่ใน #include <msclr \ *. h> (เช่น #include <msclr \ marshal.h>) และใน msclr :: interop namespace ดูตัวอย่างที่msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker

4
แม้ว่าจะสะดวก แต่ก็ขาดการสนับสนุนการเข้ารหัสที่เหมาะสมโดยสิ้นเชิง ดูคำถาม SO ของฉันด้วย: stackoverflow.com/questions/18894551/… . สมมติฐานของฉันคือ marshal_as แปลงสตริง Unicode เป็น ACP ใน std :: string
Mike Lischke

MS คำแนะนำคือการใช้ marshal_context และลบทิ้งหลังจากการแปลงเสร็จสิ้น ลิงค์: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko

40

คุณสามารถทำได้ง่ายๆดังนี้

#include <msclr/marshal_cppstd.h>

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

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

+1 สำหรับวิธีการแก้ปัญหาที่สั้นและเรียบง่ายและตัวอย่างการทำงานที่เรียบง่าย (แม้ว่าจะมีวงเล็บเสริมอยู่ท้ายรหัสของคุณก็ตาม)
Simon Forsberg

นี่เป็นทางออกเดียวที่ตอบคำถามได้โดยตรง
Jiminion

10
อืม ... 33 โหวตสำหรับคำตอบที่ได้รับมาแล้วกว่า 2 ปีก่อนหน้านี้โดยมีโค้ดเกือบบรรทัดเดียวกัน เคารพในการได้รับคะแนนมากมายสำหรับสิ่งนั้น ;-)
Beachwalker

20

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

#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
คำแปลภาษาอังกฤษ: "ฉันจะตอบกลับโพสต์นี้ด้วย: p. นี่คือหน้าที่ของฉัน"
ศิวะบุตร

9

นี่คือกิจวัตรการแปลงบางส่วนที่ฉันเขียนไว้เมื่อหลายปีก่อนสำหรับโครงการ c ++ / cli ควรทำยังใช้งานได้

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หรือเขียนโดยใช้ namespace System :: Runtime :: InteropServices; .
neo

6

ฉันใช้เวลาหลายชั่วโมงในการพยายามแปลงค่า ToString จาก listbox ของ windows เป็นสตริงมาตรฐานเพื่อที่ฉันจะได้ใช้กับ fstream เพื่อส่งออกเป็นไฟล์ txt Visual Studio ของฉันไม่ได้มาพร้อมกับไฟล์ส่วนหัวของจอมพลซึ่งมีหลายคำตอบที่ฉันพบว่าใช้ หลังจากลองผิดลองถูกมากมายในที่สุดฉันก็พบวิธีแก้ปัญหาที่ใช้ 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;

และนี่คือหน้า MSDN พร้อมตัวอย่าง: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

ฉันรู้ว่ามันเป็นวิธีแก้ปัญหาที่ค่อนข้างง่าย แต่ต้องใช้เวลาหลายชั่วโมงในการแก้ไขปัญหาและไปที่ฟอรัมต่างๆเพื่อค้นหาสิ่งที่ใช้งานได้ในที่สุด


6

ฉันพบวิธีง่ายๆในการรับ std :: string จาก String ^ คือการใช้ sprintf ()

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

ไม่ต้องเรียกฟังก์ชั่นจอมพล!

อัปเดตขอบคุณ Eric ฉันได้แก้ไขโค้ดตัวอย่างเพื่อตรวจสอบขนาดของสตริงอินพุตเพื่อป้องกันไม่ให้บัฟเฟอร์ล้น


1
เป็นการตัดสินใจที่น่าสงสัยที่จะแนะนำช่องโหว่บัฟเฟอร์ล้นในโค้ดของคุณเพียงเพื่อหลีกเลี่ยงฟังก์ชันการโทรที่ออกแบบมาเป็นพิเศษสำหรับสตริงมาร์แชล
Eric

ฉันแค่นำเสนอวิธีการที่แตกต่างออกไปหากมีคนไม่ต้องการใช้ฟังก์ชันจอมพล ฉันได้เพิ่มการตรวจสอบขนาดเพื่อป้องกันการล้น
โยนก 319

@Eric ภายในเป็นมาร์แชลสำหรับคุณ ดูคำตอบ SO นี้สำหรับรายละเอียด หากคุณตรวจสอบขนาดล่วงหน้าคุณจะไม่มีปัญหาล้นและรหัสจะสะอาดกว่ามาก
โยนก 316

4

C # ใช้รูปแบบ UTF16 สำหรับสตริง
ดังนั้นนอกจากการแปลงประเภทแล้วคุณควรคำนึงถึงรูปแบบจริงของสตริงด้วย

เมื่อคอมไพล์สำหรับ ชุดอักขระแบบหลายไบต์ Visual Studio และ Win API จะถือว่า UTF8 (การเข้ารหัส Windows ที่แท้จริงคือWindows-28591 )
เมื่อคอมไพล์สำหรับUnicode Character set Visual studio และ Win API จะถือว่า UTF16

ดังนั้นคุณต้องแปลงสตริงจากรูปแบบ UTF16 เป็น UTF8 เช่นกันไม่ใช่แค่แปลงเป็น std :: string
สิ่งนี้จะจำเป็นเมื่อทำงานกับรูปแบบหลายอักขระเช่นภาษาที่ไม่ใช่ภาษาละตินบางภาษา

แนวคิดคือการตัดสินใจว่าstd::wstring จะแสดงถึงUTF16เสมอ
และstd::string มักจะแสดงให้เห็นถึงUTF8

สิ่งนี้ไม่ได้บังคับใช้โดยคอมไพเลอร์ แต่เป็นนโยบายที่ดีที่ควรมี

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

หรือมีไวยากรณ์ที่กะทัดรัดกว่านี้:

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
ฉันแค่ต้องการเน้นย้ำถึงความสำคัญของการแปลงเป็น UTF8 ในกรณีการใช้งานของฉัน: ฉันต้องการส่งเส้นทางไฟล์ที่ได้รับจาก Win32 OpenFileDialog (ซึ่งชื่อไฟล์ที่มีอักขระหลายไบต์เป็นไปได้เช่นชื่อไฟล์ที่มีอักขระเอเชีย) ไปยังรหัสเครื่องยนต์ผ่าน std :: string ดังนั้นการแปลงเป็น UTF8 จึงมีความสำคัญ ขอบคุณสำหรับคำตอบที่ยอดเยี่ยม!
Jason McClinsey

0

ฉันชอบที่จะอยู่ห่างจากจอมพล

Using CString newString(originalString);

ดูเหมือนจะสะอาดและเร็วขึ้นมากสำหรับฉัน ไม่ต้องกังวลกับการสร้างและลบบริบท


0

// ฉันใช้ VS2012 เพื่อเขียนโค้ดด้านล่าง - convert_system_string เป็น 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;
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.