如何通过 IntPtr 将 c++ 数组编组为 c#
Posted
技术标签:
【中文标题】如何通过 IntPtr 将 c++ 数组编组为 c#【英文标题】:how to marshal c++ array to c# via IntPtr 【发布时间】:2014-04-08 13:36:36 【问题描述】:考虑以下设置:带有 c++ 库的 c# 应用程序。 c# 元素通过回调从 c++ 填充。在 c# 端回调定义如下:
void callbackTester(IntPtr pData, UInt32 length)
int[] data = new int[length];
Marshal.Copy(pData, data, (int)0, (int)length);
//using data.. on c#
现在,c++ 端的回调定义如下:
typedef void (__stdcall *func)(uint8_t* pdata, uint32_t length);
而 c++ 正在使用这样的回调:
void onData()
std::vector<uint8_t> dataToCallback;
// fill in dataToCallback
_callback(&(dataToCallback[0]), dataToCallback.size());
// where _callback is a pointer to that c# function
我的任务:在 c# 端使用回调从 c++ 端获取数组。
所以,当 c++ 对象调用 onData() 函数时,它会从 c# 调用我的回调。到目前为止,一切都很好。我制作了一个 c++ 测试程序,它使用它,并且我在回调端正确接收数组。如果我在 c# 测试器上使用它,我会收到废话。
例如:如果我发送 1, 1 的 uint8_t 数组,我将获得 1, 1 用于 c++ 测试器,并且我在 c# 端获得 0xfeeeabab, 0xfeeefeee ...显然,转换uint8_t* c++ 指针和 IntPtr c# 之间的工作不符合我的预期。
有什么建议吗?非常感谢。
【问题讨论】:
据我所知 uint8_t != (C#)int.正确的应该是字节。 std::vector 也不是一个数组,我怀疑你可以像这样将它复制到 C#。 @floele 你在正确和错误的地方混在一起。 int!=uint8_t, int 是一个 32 位整数。 C# 中的byte[]
可以工作。 std::vector 的底层数据结构是一个数组,因此可以正常工作。提示:使用 std::vector.data 代替 &(dataToCallback[0])。
uint8_t 被“投射”到 IntPtr 而不是 UIntPtr,因为 Marshal.Copy 只接受 IntPtr。你还能如何在 c# 端获取数据?
@etwas77 C# 中的 IntPtr 用词不当,它实际上等同于 c++ void*
。它只是一个内存位置。
首先,您要做的是通过 C# 函数的函数指针从 C++ 调用 C# 函数?
【参考方案1】:
问题似乎是 C++ uint8_t
是无符号字节,而 C# int
是有符号 4 字节整数。所以你有一个简单的类型不匹配。匹配uint8_t
的C# 类型是byte
。
你的回调应该是:
void callbackTester(IntPtr pData, uint length)
byte[] data = new byte[length];
Marshal.Copy(pData, data, 0, (int)length);
【讨论】:
【参考方案2】:要检查的一件事是,在 C# 方面,您期望每个元素为 int-4 字节(“int[] 数据”),但在 C++ 中,您只为每个元素分配 uint8-1 字节。
调整分配或长度使用,您可能会遇到访问冲突,这就是您看到魔术字节 [1] 的原因。
[1]http://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_debug_values
【讨论】:
不确定您的意思。我在 c++ 端提供正确的数据(我在调试器中看到它)。当我登陆 c# 端(仍在调试器上)并使用 IntPtr 和长度在那里初始化数组时,我得到了那个东西。长度转移确定。显然 IntPtr 指向不正确的地址.. 有什么问题? 查看此示例:inphamousdevelopment.wordpress.com/2012/10/01/…以上是关于如何通过 IntPtr 将 c++ 数组编组为 c#的主要内容,如果未能解决你的问题,请参考以下文章
Unity c#intptr到没有大小信息的字节数组[重复]