【问题标题】:Copy unmanaged data into managed array将非托管数据复制到托管数组中
【发布时间】:2023-03-03 20:07:01
【问题描述】:

我需要使用 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”

标签: c++-cli


【解决方案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 构造函数可以将其作为参数。

      【讨论】:

        猜你喜欢
        • 2011-03-13
        • 2011-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-19
        • 2011-09-15
        • 2013-03-14
        • 1970-01-01
        相关资源
        最近更新 更多