Преобразовать строку [] в C # в Char * [] в C ++ - PullRequest
0 голосов
/ 11 января 2012

В настоящее время я использую Visual Studio 2010. Я впервые пишу оболочку для класса C ++.Класс в C ++ выглядит следующим образом:

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

Я создал заголовочный файл, который выглядит следующим образом:

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

, а класс файла .cpp выглядит так:

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

Я выяснил, как упорядочить данные регулярной строки, но я не уверен, как преобразовать массив String в char*[].Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 11 января 2012

Следующее является идеально эффективным (минимальное копирование) и безопасным от исключений:

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

(Обратите внимание, что number не нужно передавать управляемой функции, так как это может быть выведено из длины массива.)

В качестве альтернативы можно включить предложение Бена Фойгта использовать 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]);
}
0 голосов
/ 12 января 2012

Вот версия, которую можно многократно использовать (в комплекте с демонстрацией), которая улучшает ответ @ ildjarn за счет сокращения количества выделений и улучшения локальности. Он также использует выбранную вами кодировку, например 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;
}
...