将非托管数据复制到托管数组中
Posted
技术标签:
【中文标题】将非托管数据复制到托管数组中【英文标题】:Copy unmanaged data into managed array 【发布时间】:2011-06-19 14:34:19 【问题描述】:我需要使用 C++/CLI(数组)将本机(即非托管)数据(字节*)复制到托管字节数组。
我试过 Marshal::Copy (数据由 const void* 数据指向,是 dataSize 字节)
array<byte>^ _Data=gcnew array<byte>(dataSize);
System::Runtime::InteropServices::Marshal::Copy((byte*)data, _Data, 0, dataSize);
这给出了错误 C2665:16 个重载中没有一个可以转换所有参数。然后我尝试了
System::Runtime::InteropServices::Marshal::Copy(new IntPtr(data), _Data, 0, dataSize);
产生错误 C2664:参数 1 无法从“const void*”转换为“__w64 int”。
那么如何做到这一点,Marshal::Copy 确实是“最好”(最简单/最快)的方法吗?
【问题讨论】:
顺便说一句-“系统::运行时::InteropServices::Marshal::Copy((IntPtr)data, _Data, 0, dataSize);"给出错误 C2440 - 无法将“const void*”转换为“System::IntPtr” 【参考方案1】:正如您所指出的,Marshal::Copy
(和一般的 .NET)不是const
-safe。
但是,通常的 C 和 C++ 函数是。你可以写:
array<byte>^ data_array =gcnew array<byte>(dataSize);
pin_ptr<byte> data_array_start = &data_array[0];
memcpy(data_array_start, data, dataSize);
或避免固定:
array<byte>^ data_array =gcnew array<byte>(dataSize);
for( int i = 0; i < data_array->Length; ++i )
data_array[i] = data[i];
【讨论】:
我喜欢避免固定【参考方案2】:“IntPtr”只是“void *”的包装。您不需要新语法,只需使用显式转换运算符即可。
System::Runtime::InteropServices::Marshal::Copy( IntPtr( ( void * ) data ), _Data, 0, dataSize );
应该可以。
【讨论】:
谢谢,不过请看我上面的评论。但是,它似乎适用于“(IntPtr)(byte *)数据。所以,虽然它现在“有效”,但问题仍然是它是否可以做得更好。恐怕,没有办法跳过副本。 @user 为什么要投射两次?您只需要将“数据”设置为( IntPtr ),因为您已将其声明为“const void *”。这只是使它适合“Marshal.Copy”的方法签名,将您的数据声明更改为 IntPtr,您将不需要演员表。 不幸的是,我无法从“const void*”更改“数据”,因为它来自第三方库。而且,如上所述,(IntPtr)data 给出错误 C2440 就像这样 sn-p: "const void* vp; IntPtr ip=(IntPtr)vp;" @User const void * data = ...; IntPtr ptr = IntPtr( ( void * ) 数据); // 现在用户指针【参考方案3】:所有这些答案都围绕着原始问题中的真正误解.. 犯的基本错误是这段代码:
System::Runtime::InteropServices::Marshal::Copy(new IntPtr(data),
_Data,
0,
dataSize)
不正确.. 您没有新建(或 gcnew)IntPtr。它是一个值类型。其中一个答案表明了这一点,但并没有指出最初的误解。正确的代码可以这样表示:
System::Runtime::InteropServices::Marshal::Copy(IntPtr((void *)data),
_Data,
0,
dataSize)
当我第一次开始使用这些结构时,这让我很困惑..
IntPtr 是一个 C# 结构.. 一个值类型。
【讨论】:
【参考方案4】:C++/CLI 编译器对此有点迟钝。 IntPtr 的正式定义是“本机整数”,它不是指针类型。然而,C++ 语言只允许将 void* 转换为指针类型。 CLI 支持指针类型,但接受它们的框架方法很少。 Marshal::Copy() 没有。三个 IntPtr 构造函数之一。
您必须使用强制转换或使用 IntPtr 构造函数来敲击编译器。任何人都在猜测这是否仍然可以在 128 位操作系统上运行,我暂时不会担心。
【讨论】:
【参考方案5】:System::Runtime::InteropServices::Marshal::Copy(new IntPtr((void*)data), _Data, 0, dataSize);
注意 (void*),它 从 (const void*) 进行类型转换,以便新的 IntPtr 构造函数可以将其作为参数。
【讨论】:
以上是关于将非托管数据复制到托管数组中的主要内容,如果未能解决你的问题,请参考以下文章