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

时间:2011-08-25 13:14:19

标签: c++ interop c++-cli

在C ++ / CLI中,将字符串数组转换为本机字符**的最有效方法是什么?

我这样做:

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;
// ...

什么,如果有什么需要改进的话?从内存管理的角度来看,这样可以吗?如果需要,我可以更改someNativeFunction的参数。

谢谢。

1 个答案:

答案 0 :(得分:4)

除了固定指针在传递给someNativeFunction()之前超出范围的问题之外,代码可以简化以便更清晰,特别是如果您使用的是MSVC2008或更新版本。有关如何转换单个字符串(扩展到数组应该是微不足道的)的信息,请参阅this page

<强>编辑:

如果您需要ANSI字符串const char*,那么复制是不可避免的,因为.NET字符串是Unicode(UTF-16)。在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!

这与您的代码示例类似,但不需要指针固定和reinterpret_cast - 。

如果您愿意处理const wchar_t*中的宽字符串someNativeFunction(),您可以直接使用(固定的)内部数据,但是,您必须确保指针保持固定,直到{{ 1}}返回,正如评论中指出的那样,可能会对GC性能产生负面影响。

如果您要编组许多字符串并且性能最受关注,那么您可以 在将所有内容传递给someNativeFunction()之前,将编组拆分为多个线程。在此之前,我建议您分析您的应用程序,看看转换是否确实是一个瓶颈,或者是否更好地将工作重点放在其他地方。

编辑#2:

要获取UTF-8编码的本机字符串,您可以使用修改后的代码版本:

someNativeFunction()

如果您担心速度,可以为本地字符串预先分配一个大缓冲区(如果您知道只有有限的数量)或使用池存储。

编辑#3:(OG Dude) 刚修正了一些小错字。