如何将struct作为参数从c ++ / cli传递给c ++

时间:2014-04-08 08:36:10

标签: c++ struct c++-cli

我的代码有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 ++,但是我搜索了很多,没有找到确切的答案。

我确实找到了一些代码,但它使用了指针而不是结构,我也尝试使用指针,但我也有同样的错误。

由于

3 个答案:

答案 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) .