简体   繁体   English

将C#中的String []转换为C ++中的Char * []

[英]Convert a String[] in C# to a Char *[] in C++

I am currently using Visual Studio 2010. This is my first time writing a wrapper for a C++ class. 我当前正在使用Visual Studio2010。这是我第一次为C ++类编写包装。 The class in C++ looks like this: C ++中的类如下所示:

bool exampleCode(char* arrayOfStrings[], int number, char* regularString)

I created the header file which looks like: 我创建的头文件如下所示:

bool exampleCode(array<String^>^ arrayOfStrings, int number, String^ regularString)

and the .cpp file class looks like: .cpp文件类如下所示:

bool exampleCode(array<String^>^ arrayOfStrings, int number, System::String^ regularString)

I figured out how to marshal the regularString data but I'm not sure how to convert the String array into a char*[] . 我想出了如何封送RegularString数据,但不确定如何将String数组转换为char*[] Any help would be appreciated. 任何帮助,将不胜感激。

The following is ideally efficient (minimal copying) and exception-safe: 以下是理想的高效(最小复制)和异常安全的消息:

#include <algorithm>
#include <memory>
#include <vector>

using System::IntPtr;
using System::String;
using System::Runtime::InteropServices::Marshal;

bool exampleCodeManaged(array<String^>^ arrayOfStrings, String^ regularString)
{
    auto deleter = [](char* p) { Marshal::FreeHGlobal(IntPtr(p)); };
    typedef std::unique_ptr<char[], decltype(deleter)> cstr_t;
    auto make_cstr = [&deleter](String^ s)
    {
        return cstr_t(
            static_cast<char*>(Marshal::StringToHGlobalAnsi(s).ToPointer()),
            deleter
        );
    };

    std::vector<cstr_t> cstrs;
    cstrs.reserve(arrayOfStrings->Length);
    for each (String^ s in arrayOfStrings)
        cstrs.push_back(make_cstr(s));

    std::vector<char*> ptrs;
    ptrs.reserve(cstrs.size());
    std::for_each(
        cstrs.begin(),
        cstrs.end(),
        [&ptrs](cstr_t& cstr) { ptrs.push_back(cstr.get()); }
    );

    auto reg_cstr = make_cstr(regularString);

    return exampleCode(ptrs.data(), arrayOfStrings->Length, reg_cstr.get());
}

(Note that number does not need to be passed in to the managed function as it can be deduced from the array's length.) (请注意, number并不需要传递中,因为它可以从数组的长度推断的管理功能。)

Alternatively, incorporating Ben Voigt's suggestion to use std::string instead of the Marshal class: 或者,结合Ben Voigt的建议使用std::string代替Marshal类:

#include <algorithm>
#include <string>
#include <vector>
#include <msclr/marshal_cppstd.h>

using System::String;

bool exampleCodeManaged(array<String^>^ arrayOfStrings, String^ regularString)
{
    using msclr::interop::marshal_as;

    std::vector<std::string> strs;
    strs.reserve(arrayOfStrings->Length);
    for each (String^ s in arrayOfStrings)
        strs.push_back(marshal_as<std::string>(s));

    std::vector<char*> ptrs;
    ptrs.reserve(strs.size());
    std::for_each(
        strs.begin(),
        strs.end(),
        [&ptrs](std::string& s) { ptrs.push_back(&s[0]); }
    );

    auto reg = marshal_as<std::string>(regularString);

    return exampleCode(ptrs.data(), arrayOfStrings->Length, &reg[0]);
}

Here's an easily reusable version (complete with demonstration) that improves on @ildjarn's answer by reducing the number of allocations and improving locality. 这是一个易于重用的版本(带有演示),它通过减少分配数量和改善局部性来改进@ildjarn的答案。 It also uses your choice of encoding such as UTF-8. 它还使用您选择的编码,例如UTF-8。

#include <iostream>
#include <vector>

#include <windows.h>
#include <vcclr.h>

using namespace System;

template <typename T>
struct advanced_marshal;

template <>
struct advanced_marshal<char*[]>
{
    char** get() { return &m_strings[0]; }

    advanced_marshal( array<System::String^>^ strings, UINT code_page = CP_ACP ) : m_strings(strings->Length)
    {
        if (int count = strings->Length) {
            int i;
            size_t total_length_estimate = count; // one NUL byte per string
            for( i = 0; i < count; ++i ) {
                total_length_estimate += strings[i]->Length * 4;
            }

            m_buffer.resize(total_length_estimate);
            auto tail = m_buffer.begin(), end = m_buffer.end();
            i = 0;
            do {
                m_strings[i] = &*tail;
                pin_ptr<const WCHAR> pwsz = PtrToStringChars(strings[i]);
                tail += 1 + WideCharToMultiByte(code_page, 0, pwsz, strings[i]->Length, &*tail , end - tail, nullptr, nullptr);

                ++i;
            } while (i < count);
        }
    }

    advanced_marshal(advanced_marshal<char*[]>&& other) { m_buffer.swap(other.m_buffer); m_strings.swap(other.m_strings); }

private:
    advanced_marshal(const advanced_marshal<char*[]>&); // = delete
    void operator=(const advanced_marshal<char*[]>&); // = delete

    std::vector<char> m_buffer;
    std::vector<char*> m_strings;
};

void print_some_strings( char* strings[], int num )
{
    for( int i = 0; i < num; ++i )
        std::cout << strings[i] << "\n";

    std::cin.get();
}

int main(array<System::String ^> ^args)
{
    print_some_strings(advanced_marshal<char*[]>(args).get(), args->Length);
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM