C ++ / CLI Chuyển đổi từ System :: String ^ sang std :: string


90

Ai đó có thể vui lòng đăng một mã đơn giản có thể chuyển đổi,

System::String^

Đến,

C ++ std::string

Tức là, tôi chỉ muốn gán giá trị của,

String^ originalString;

Đến,

std::string newString;

Câu trả lời:


38

Kiểm tra System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni()và bạn bè của nó.

Xin lỗi không thể gửi mã ngay bây giờ; Tôi không có VS trên máy này để kiểm tra biên dịch trước khi đăng.


159

Đừng cuộn của riêng bạn, hãy sử dụng các trình bao bọc tiện dụng (và có thể mở rộng) này do Microsoft cung cấp.

Ví dụ:

#include <msclr\marshal_cppstd.h>

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

2
thx cho liên kết hữu ích này, gợi ý này đã giúp tôi tiết kiệm rất nhiều mã. như một lưu ý phụ: các mẫu / lớp nằm trong #include <msclr \ *. h> (ví dụ: #include <msclr \ marshal.h>) và trong không gian tên msclr :: interop, hãy xem ví dụ tại msdn.microsoft.com /de-de/library/vstudio/bb384859(v=vs.90).aspx )
Beachwalker

4
Mặc dù điều này thuận tiện nhưng nó hoàn toàn thiếu hỗ trợ mã hóa thích hợp. Xem thêm câu hỏi SO của tôi: stackoverflow.com/questions/18894551/… . Giả định của tôi là marshal_as chuyển đổi chuỗi Unicode thành ACP trong std :: string.
Mike Lischke

Khuyến nghị của MS là sử dụng marshal_context và xóa nó sau khi chuyển đổi xong. Liên kết: msdn.microsoft.com/en-us/library/bb384856.aspx
Ruslan Makrenko

40

Bạn có thể dễ dàng làm điều này như sau

#include <msclr/marshal_cppstd.h>

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

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

1 cho một giải pháp ngắn và đơn giản và gương sáng làm việc đơn giản (mặc dù có một ngoặc thêm ở phần cuối của mã của bạn)
Simon Forsberg

Đây là giải pháp duy nhất trực tiếp trả lời câu hỏi.
Jiminion

8
hmm ... 33 lượt ủng hộ cho một câu trả lời đã được đưa ra hơn 2 năm trước đó với các dòng mã gần giống nhau. tôn trọng vì đạt được rất nhiều điểm cho điều đó. ;-)
Beachwalker

20

Điều này đã làm việc cho tôi:

#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
Bản dịch tiếng Anh: "Tôi cũng sẽ trả lời bài đăng này: p. Đây là chức năng của tôi."
sivabudh

9

Dưới đây là một số quy trình chuyển đổi tôi đã viết nhiều năm trước cho một dự án c ++ / cli, chúng vẫn sẽ hoạt động.

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, Sử dụng System :: Runtime :: InteropServices :: Marshal hoặc viết bằng cách sử dụng không gian tên Hệ thống :: Runtime :: InteropServices; .
neo

6

Tôi đã dành hàng giờ để cố gắng chuyển đổi giá trị ToString của hộp danh sách windows thành một chuỗi tiêu chuẩn để tôi có thể sử dụng nó với fstream để xuất ra tệp txt. Visual Studio của tôi không đi kèm với các tệp tiêu đề thống nhất mà một số câu trả lời tôi tìm thấy được cho là sử dụng. Sau rất nhiều lần thử và sai, cuối cùng tôi đã tìm ra giải pháp cho vấn đề chỉ sử dụng 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;

Và đây là trang MSDN với ví dụ: http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx

Tôi biết đó là một giải pháp khá đơn giản nhưng điều này đã khiến tôi mất GIỜ khắc phục sự cố và truy cập một số diễn đàn để cuối cùng tìm thấy thứ gì đó hoạt động.


6

Tôi đã tìm thấy một cách dễ dàng để lấy std :: string từ String ^ là sử dụng sprintf ().

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

Không cần gọi các hàm Nguyên soái!

CẬP NHẬT Cảm ơn Eric, tôi đã sửa đổi mã mẫu để kiểm tra kích thước của chuỗi đầu vào để ngăn chặn tràn bộ đệm.


1
Đó là một quyết định gây tò mò khi giới thiệu lỗ hổng tràn bộ đệm trong mã của bạn chỉ để tránh gọi các hàm được thiết kế đặc biệt cho các chuỗi marshall.
Eric

Tôi chỉ đơn giản là trình bày một cách tiếp cận khác nếu ai đó không muốn sử dụng các hàm thống chế. Tôi đã thêm kiểm tra kích thước để ngăn tràn.
Ionian316

@Eric Nội bộ nó đang sắp xếp cho bạn. Xem câu trả lời SO này để biết chi tiết. Nếu bạn kiểm tra kích thước trước đó, bạn sẽ không gặp bất kỳ sự cố tràn nào và mã sạch hơn nhiều.
Ionian316

4

C # sử dụng định dạng UTF16 cho các chuỗi của nó.
Vì vậy, bên cạnh việc chỉ chuyển đổi các kiểu, bạn cũng nên biết về định dạng thực tế của chuỗi.

Khi biên dịch cho bộ ký tự nhiều byte, Visual Studio và Win API giả định UTF8 (Trên thực tế mã hóa cửa sổ là Windows-28591 ).
Khi biên dịch cho bộ ký tự Unicode, Visual studio và Win API giả sử UTF16.

Vì vậy, bạn cũng phải chuyển đổi chuỗi từ định dạng UTF16 sang UTF8 và không chỉ chuyển đổi sang std :: string.
Điều này sẽ trở nên cần thiết khi làm việc với các định dạng nhiều ký tự như một số ngôn ngữ không phải là ngôn ngữ latin.

Ý tưởng là quyết định rằng std::wstring luôn đại diện cho UTF16 .
std::string luôn đại diện cho UTF8 .

Điều này không được thực thi bởi trình biên dịch, đó là một chính sách tốt hơn.

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

Hoặc có nó trong một cú pháp nhỏ gọn hơn:

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
Tôi chỉ muốn nhấn mạnh tầm quan trọng của việc chuyển đổi sang UTF8 trong trường hợp sử dụng của mình: Tôi cần chuyển đường dẫn tệp nhận được từ Win32 OpenFileDialog (nơi có thể sử dụng tên tệp có nhiều ký tự, ví dụ: tên tệp chứa ký tự Châu Á) sang mã động cơ thông qua một std :: string, vì vậy việc chuyển đổi sang UTF8 rất quan trọng. Cảm ơn vì câu trả lời xuất sắc!
Jason McClinsey

0

Tôi thích tránh xa cảnh sát trưởng.

Using CString newString(originalString);

Có vẻ sạch hơn và nhanh hơn nhiều đối với tôi. Không cần phải lo lắng về việc tạo và xóa ngữ cảnh.


0

// Tôi đã sử dụng VS2012 để viết mã bên dưới-- convert_system_string thành 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;
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.