简体   繁体   English

将C ++ / CLI字符串数组转换为本机C ++ char **

[英]Conversion of C++/CLI array of strings to native C++ char**

In C++/CLI, What's the most efficient way to convert an array of strings to native char**? 在C ++ / CLI中,将字符串数组转换为本机char **的最有效方法是什么?

I am doing this: 我这样做:

array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
int numTokens = tokenArray->Length;
char** ptr = new char* [numTokens];
for(int i = 0; i < numTokens; i++)
    {
        // See: http://stackoverflow.com/questions/6596242/
        array<Byte>^ encodedBytes = Text::Encoding::UTF8->GetBytes(tokenArray[i]);
        pin_ptr<Byte> pinnedBytes = &encodedBytes[0];
        ptr[i] = reinterpret_cast<char*>(pinnedBytes);
    }
int myResult = someNativeFunction(ptr, numTokens);
delete ptr;
// ...

What, if anything should be improved? 什么,如果有什么需要改进? Is this ok from a memory management point of view? 从内存管理的角度来看,这样可以吗? I can change the parameters of someNativeFunction if need be. 如果需要,我可以更改someNativeFunction的参数。

Thank you. 谢谢。

Apart from the problem with pinned pointers going out of scope before being passed to someNativeFunction() , the code can be simplified for better clarity especially if you're using MSVC2008 or newer. 除了固定指针在传递给someNativeFunction()之前超出范围的问题之外,代码可以简化以便更清晰,特别是如果您使用的是MSVC2008或更新版本。 See this page for information on how to convert a single string (extending to an array should be trivial). 有关如何转换单个字符串的信息,请参阅此页面 (扩展到数组应该是微不足道的)。

Edited: 编辑:

If you need ANSI strings const char* then making a copy is inevitable since .NET Strings are Unicode (UTF-16). 如果你需要ANSI字符串const char*那么复制是不可避免的,因为.NET字符串是Unicode(UTF-16)。 On MSVC2008 and newer, your code may look as follows: 在MSVC2008及更高版本上,您的代码可能如下所示:

#include <msclr/marshal.h>
using namespace msclr::interop;

marshal_context context;
array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
char** tokensAsAnsi = new char* [tokenArray->Length];

for(int i = 0; i < tokenArray->Length; i++)
{
    tokensAsAnsi[i] = context.marshal_as<const char*>(tokenArray[i]);
}
int myResult = someNativeFunction(ptr, tokensAsAnsi);

// The marshalled results are freed when context goes out of scope
delete[] tokensAsAnsi;    // Please note you must use delete[] here!

This does similar job to your code sample but without the need of pointer pinning and reinterpret_cast -ing. 这与您的代码示例类似,但不需要指针固定和reinterpret_cast -ing。

If you are willing to deal with wide string const wchar_t* in someNativeFunction() , you can use the (pinned) internal data directly, However, you'll have to ensure the pointers remain pinned until someNativeFunction() returns which, as pointed out in the comments, may negatively influence the GC performance. 如果你愿意在someNativeFunction()处理宽字符串const wchar_t* ,你可以直接使用(固定的)内部数据,但是,你必须确保指针保持固定,直到someNativeFunction()返回,正如指出的那样在评论中,可能会对GC性能产生负面影响。

If you're about to marshall many strings and performance is of utmost concern, you could split the marshalling across several threads before passing everything to someNativeFunction() . 如果您要编组许多字符串并且性能是最令人担忧的,那么在将所有someNativeFunction()传递给someNativeFunction()之前,您可以将编组拆分为多个线程。 Before doing that, I'd reccommend profiling your application to see if the conversion really is a bottleneck or whether it's better to focus efforts elsewhere. 在此之前,我建议您分析您的应用程序,看看转换是否确实是一个瓶颈,或者是否更好地将工作重点放在其他地方。

Edited #2: 编辑#2:

To get the native string in UTF-8 encoding, you can do with a modified version of your code: 要获得UTF-8编码的本机字符串,您可以使用修改后的代码版本:

array<String^>^ tokenArray = gcnew array<String^> {"TokenONE", "TokenTWO"};
char** tokensAsUtf8 = new char* [tokenArray->Length];

for(int i = 0; i < tokenArray->Length; i++)
{
    array<Byte>^ encodedBytes = Text::Encoding::UTF8->GetBytes(tokenArray[i]);

    // Probably just using [0] is fine here
    pin_ptr<Byte> pinnedBytes = &encodedBytes[encodedBytes->GetLowerBound(0)];

    tokensAsUtf8[i] = new char[encodedBytes->Length + 1]; 
    memcpy(
        tokensAsUtf8[i], 
        reinterpret_cast<char*>(pinnedBytes),
        encodedBytes->Length
        );

    // NULL-terminate the native string
    tokensAsUtf8[i][encodedBytes->Length] = '\0'; 

}
int myResult = someNativeFunction(ptr, tokensAsAnsi);

for(int i = 0; i < tokenArray->Length; i++) delete[] tokensAsUtf8[i];
delete[] tokensAsUtf8;    

If you're concerned about speed, you could pre-allocate a large buffer for the native strings (if you know there will only be a limited amount) or use pool storage. 如果您担心速度,可以为本机字符串预分配一个大缓冲区(如果您知道只有有限的数量)或使用池存储。

Edited #3:(OG Dude) Just fixed some minor typos. 编辑#3:(OG Dude)刚刚修正了一些小错字。

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

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