我的代码有3个部分:c#,c ++ / cli,c ++。
在c#中,我有一个结构。结构定义为传递参数。
//c#
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public struct NDeviceDest
{
public uint IP;
public uint pos;
}
然后在c ++ / cli中,我有一个使用 NDeviceDest
的函数//c++/CLI
byte NDockMaster::Init(NDeviceDest pos, uint param)
{
m_pDockMaster->Init(static_cast<DeviceDest*>pos, param);
}
* m_pDockMaster *是指向本机类型的指针。
Init 的成员函数在c ++中定义为()
//c++
struct DeviceDest
{
UINT32 IP;
unsigned int pos;
};
class DockMaster
{
public:
byte Init(DeviceDest* dest, UINT32 param)
{
return 0;
}
}
DeviceDest 定义为与 NDeviceDest 完全相同,以传递参数。
问题:
在我的c ++ / cli代码中,我使用* static_cast *来进行类型更改。但我得到了编译错误:
error C2440: 'static_cast' : cannot convert from 'NDeviceDest' to 'DeviceDest *'
我是c ++ / cli的新手,但我认为必须有一种方法让编译器知道NDeviceDest是DeviceDest并让我编译代码并将值从c#传递给cli然后传递给c ++,但是我搜索了很多,没有找到确切的答案。
我确实找到了一些代码,但它使用了指针而不是结构,我也尝试使用指针,但我也有同样的错误。
由于
答案 0 :(得分:4)
不,编译器不允许你这样做。甚至没有C风格的演员表或reinterpret_cast&lt;&gt;()都可以使用,这是你可用的最大武器。
这是一个很好的理由,托管结构与非托管结构非常不兼容。第一个问题是布局,结构成员的确切顺序和偏移量。从技术上讲,这是一个较小的问题,CLR已经使尝试保持相同。通常它是一个匹配,而不是总是。您可以在this post中找到更多详细信息。
更大的问题是存储,托管结构往往分配在可以随机更改的地址。具有垃圾收集器的副作用,其职责之一不仅是释放未使用的内存而且还压缩堆。 非常与您的本机代码使用您传递的指针的方式不兼容,随机将在不正确的地址取消引用该结构。要么是因为它释放了封闭对象,要么是因为它移动了它。非常难以调试,因为它很少发生并且完全不确定,因为它依赖于分配的其他托管线程。
所以它只是禁止它。必须对结构进行封送处理,将其复制到非托管内存中并重新排列以匹配本机布局。通用辅助函数是Marshal :: StructureToPtr()。但对于如此小的结构来说,完全没有必要,自己复制字段会更快更简单:
Byte Init(NDeviceDest pos, unsigned param) {
DeviceDest unmanagedPos = { pos.IP, pos.pos };
m_pDockMaster->Init(&unmanagedPos, param);
//...
}
满足要求,保证了正确的布局。并且在稳定的内存中分配,GC不会混淆堆栈位置,并且在方法体执行期间内存是稳定的。如果需要说,可能不是,请确保“DockMaster”不存储传递的指针。
答案 1 :(得分:0)
您看到的错误是static_cast不允许从struct
转换(转换)为struct *
。因此,c ++ / cli接口中的正确调用将是
m_pDockMaster->Init(static_cast<DeviceDest*>(&pos), param);
答案 2 :(得分:0)
如果这是一个类查找问题,如果你正在使用指针,并且你确定你的编组是正确的,请尝试使用reinterpret_cast。
m_pDockMaster->Init(reinterpret_cast<DeviceDest*>pos, param);
但是乍一看,您正在尝试将非指针类型转换为指针类型。 您应该使用NDeviceDest * pos作为输入参数或
m_pDockMaster->Init(static_cast<DevideDest*>&pos,param) .