如何在c++中构建动态数组并将其返回到c# /. net

本文关键字:返回 net 数组 c++ 动态 构建 | 更新日期: 2023-09-27 17:54:00

我必须找到在c++ Win32端构建结构体数组的方法。我没有初始项数。调整数组的大小应该非常快。

当列表被构建时,我需要将它返回到。net。因此,数组(列表)应该转换为可以在。net端轻松读取的传输,或者初始列表可以"原样"使用,只是传递指针。

提前感谢你给我的提示!

如何在c++中构建动态数组并将其返回到c# /. net

在c++中实现"动态数组"的一种非常常见的方法是使用STL的 std::vector 。在您的示例中,您可以定义一个vector<SomeData>std::vector可以动态地改变它的大小(即在运行时),根据您的要求:您可以使用它的push_backemplace_back方法用于此目的,向矢量添加新项。

然而,c#并不"理解"std::vector

要将其内容封送到c#中,您可以使用 SAFEARRAY , CLR对此非常理解。SAFEARRAY的好处是,除了数组内容之外,它还存储数组大小:它是一个自包含的数据结构。因此,你可以创建一个大小合适的SAFEARRAY,用vector中动态创建的内容填充它,并将该SAFEARRAY传递给c#。

注意,您也可以直接构建SAFEARRAY,而不传递std::vector。但是STL的vector有一个更强大的编程接口;因此,如果您希望在运行时通过push_back或emplace_back进行几项添加,则首先构建std::vector,然后将其"编组"到SAFEARRAY中,可能是更好的选择。无论如何,这取决于你的特殊需求和环境。


作为替代方案,您可以使用c++/CLI作为c++端和c#端之间的桥接层。在这种情况下,你可以使用gcnew来创建一个。net "managed" array


并且,作为另一种选择,您可以使用C接口从本机c++ DLL中导出两个函数:

  • 获取数组中项目计数的函数

  • 另一个函数,用于在输出调用者分配的缓冲区中获取实际数组数据(其大小由前一个函数返回)

在c#中,输出缓冲区指针是通过IntPtr输出参数传递的。然后可以使用Marshal.PtrToStructure封送单个数据项,并且可以使用Marshal.SizeOf增加指针,使其指向数组中的下一个项。

像这样:

// In C++:
struct SomeData
{
    /* your data fields */
};
// Export these two functions from your native DLL:
extern "C" int GetSomeDataCount( /* some params */ );
extern "C" void GetSomeData( SomeData* ptr, /* some other params */ );

// In C#:    
public struct SomeData
{
    // Map C++ data structure fields to C#
}
static extern int GetSomeDataCount( /* some params */ );
static extern void GetSomeData( [Out] out IntPtr ptr, /* some other params */ );
SomeData[] GetSomeData( /* some params */ )
{
    // Allocate an array of proper size
    SomeData[] dataArray = new SomeData[ GetSomeDataCount( /* some params */ ) ];
    // Fill the array with content from GetSomeData
    IntPtr dataPtr;
    GetSomeData( out dataPtr, /* some other params */ );
    for (int i = 0; i < dataArray.Length; i++)
    {
        dataArray[i] = Marshal.PtrToStructure(dataPtr, typeof(SomeData));
        dataPtr += Marshal.SizeOf(typeof(SomeData));
    }
    return dataArray;
}

一般来说,如果你的c++ dll是用CLI支持编译的,你可以简单地使用托管容器。如果你不想用CLI选项编译你的dll,那么你可以编写一个小的c++/CLI包装器dll,它将调用本地c++ dll中的方法,并将对象存储在托管容器中。另一个可能的解决方案是改变c++库的接口,使其按索引返回对象,支持插入和/或删除。

std::vector<CFoo> vec;
void init() {
    //read data to vec
}
CFoo getIthElement(int i) {
    return vec[i];
}
int getElementCount() {
    return vec.size();
}

所以你将在c#端使用getIthElementgetElementCount函数