如何将结构作为参数从 c++/cli 传递到 c++

How to pass struct as parameter from c++/cli to c++

本文关键字:c++ cli 参数 结构      更新时间:2023-10-16

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

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

谢谢

不,编译器不会让你这样做。 即使是C型施法或reinterpret_cast<>()也不起作用,这是你拥有的最大武器。

这是有充分理由的,托管结构与非托管结构非常不兼容。 第一个问题是布局,结构成员的确切顺序和偏移量。 从技术上讲,这是一个较小的问题,CLR 已经尝试使它们保持不变。 通常是匹配的,并非总是如此。 您将在这篇文章中找到更多详细信息。

更大的问题是存储,托管结构倾向于在可以随机更改的地址上分配。 垃圾回收器的副作用是,它的职责之一是不仅释放未使用的内存,而且还压缩堆。 与本机代码使用您传递的指针的方式非常不兼容,它会随机取消对错误地址的结构的引用。 要么是因为它释放了封闭对象,要么是因为它移动了它。 调试非常困难,因为它很少发生,并且完全不确定,因为它依赖于分配的其他托管线程。

所以它只是简单地禁止它。 必须封送结构,将其复制到非托管内存中,然后重新排列以匹配本机布局。 通用帮助程序函数是 Marshal::StructureToPtr()。 但是对于这么小的结构来说完全没有必要,自己复制字段要更快、更简单:

  Byte Init(NDeviceDest pos, unsigned param) {
      DeviceDest unmanagedPos = { pos.IP, pos.pos };
      m_pDockMaster->Init(&unmanagedPos, param);
      //...
  }

满足要求,它保证了正确的布局。 并且分配在稳定的内存中,GC 不会弄乱堆栈位置,并且内存在方法主体执行期间是稳定的。 如果需要说,可能不需要,请确保"DockMaster"不存储传递的指针。

您看到的错误是不允许static_cast从struct转换为struct *。因此,c++/cli 接口中的正确调用是

m_pDockMaster->Init(static_cast<DeviceDest*>(&pos), param);

如果这是一个类查找问题,并且如果您使用的是指针并且您确定封送处理是正确的,请尝试使用 reinterpret_cast。

m_pDockMaster->Init(reinterpret_cast<DeviceDest*>pos, param);

但乍一看,您正在尝试将非指针类型转换为指针类型。您应该使用 NDeviceDest* pos 作为输入参数,或者

m_pDockMaster->Init(static_cast<DevideDest*>&pos,param) .