繁体   English   中英

将结构体数组作为参数传递给函数

[英]Passing an array of structs to a function as a parameter

我知道这个问题已经在stackoverflow中出现了很多时间,当我开始研究这个问题时,我在检查了stackoverflow提出的所有问题之后发布了这个问题。

基本上,我想实现这一目标。 大图:将数组结构从c ++ dll传递到ac#应用程序。 这里要注意的是,数组的大小只能由c ++ dll确定。 现在我只知道,可以使用out参数作为函数参数来获取从c ++到c#的任何数组。 是的,我可以将ref作为out参数传递给c ++函数,该参数的大小未知,但已初始化为NULL。 但是我不确定这是对的还是行得通! 另一种方法是,将结构体数组作为返回值,对此我在c#中没有找到任何示例。

所以我做了:将这个问题简化为一个c ++问题

我尝试了一些示例示例,以将结构数组从函数返回到main(),从c ++ dll返回到测试c ++应用程序。 ->工作正常。 因此,作为返回值,结构数组可以正常工作。 显然,由于我不必用确切的大小初始化结构数组,因此从一开始就调用函数来填充数组!

但是要注意的是,我需要以一种可以被c#端接收的可行方式来实现它! 因此,作为函数的out参数,而不作为返回值(如果有人知道如何从c ++ dll到c#接收结构数组,请提供帮助!)。

在stackoverflow或google中,有关将结构数组传递给函数的所有问题的大小均已事先确定。 但就我而言,该功能将只能确定大小。 在调用函数之前,我不知道数组的大小。 而且,我实际上是在尝试通过一个函数调用来完成任务,因此,我不能拥有2个API,一个用于计算大小,一个用于获取数组。 这将是一个重复的任务,因为相同的功能必须执行两次,一次只能获取大小,而另一次则需要获取实际的数组,这是不可行的!

我有一个示例代码。 如果有人可以提供帮助,将不胜感激。

// structsEx.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <conio.h>
#include <vector>
#include <string>

using namespace std;
using std::vector;
using std::string;

struct example
{
    char* name; // char* or const char*. But not sure if I can have an
                // std::string.
    int age;
    char* company;
};

void passStructsRef(struct example** ex)  // Again, not sure if I can have 
                                          // std::array or std::vector since 
                                          // this will be the API I expose 
                                          // to C# side.
{
    vector<string> names = {"AAA", "BBB", "CCC", "DDD", "EEE"};
    vector<int> ages = {25, 26, 27, 28, 29, 30};
    vector<string> companies = { "AAA1", "BBB2", "CCC3", "DDD4", "EEE5" };

    *ex = new example[5];  // I think this is a problem. It only initializes 
                           // the first element and hence, I get only the 
                           // first item.
    for (int i = 0; i < 5; i++)
    {
        ex[i] = new example();  // Is this right? Not sure.. 
        ex[i]->age = ages[i];
        ex[i]->name = _strdup(names[i].c_str());
        ex[i]->company = _strdup(companies[i].c_str());
    }

    cout << "2 in function" << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << ex[i]->name << "\t" << ex[i]->age << "\t" << ex[i]->company << endl;
    }
}

int main()
{
    example ex;
    ex.age = 30;
    ex.name = "AEIOU";
    ex.company = "ABCDE";

    cout << "1" << endl;
    cout << ex.name << "\t" << ex.age << "\t" << ex.company << endl;

    cout << "2" << endl;
    example *ex2 = nullptr;
    passStructsRef(&ex2);

    for (int i = 0; i < 5; i++)
    {
        cout << ex2[i].name << "\t" << ex2[i].age << "\t" << ex2[i].company << endl;
    }

    _getch();
    return 0;
}

注释之后,我想我必须对代码进行一些注释。 我不确定我是否可以在要向C#应用程序公开的代码中使用STL数组或向量或std :: string。 这就是为什么我在这里使用new运算符的原因。 下一个可能出现的问题是删除在哪里? 好吧,我必须有另一个调用delete的API才能删除为该结构分配的内存。 当我的C#应用​​程序成功接收到我返回的所有数据并对其进行处理后,它将被调用。 那不是问题。 但是将数据发送到C#是一个问题,导致我编写了此示例C ++测试应用程序。

无需编写任何大语法或任何特殊代码即可将数据发送到C#。 如果它在C ++中工作,则必须正确导出参数和API,才能在C#中工作。 这就是为什么我试图使我的C ++完美。

希望这可以帮助。 非常感谢。

实际上,这里有两个问题。

一种是如何返回结构数组。

经典的方式是这样的:

C ++:

int getStructsLength();
int getStructs( int bufferLength, struct example* buffer ); // Returns the count of structures actually written

C#

static extern int getStructsLength();
static extern int getStructs( int bufferLength, [Out, MarshalAs( UnmanagedType.LPArray, SizeParamIndex = 0 )] example[] buffer );

另一个是如何在这些结构中返回字符串。

如果没有太多数据或调用太多,并且无法在Windows上运行,则一种简单的方法是将const char*更改为BSTR ,并相应地调整C ++代码。 这些是每种语言都知道如何跨DLL边界正确分配/取消分配的Unicode字符串。 唯一的缺点是它们相对较慢。

另一种更复杂的方法是在C#结构中声明以下字段:

 [MarshalAs(UnmanagedType.LPStr)] public string name;

在C ++中,用CoTaskMemAlloc和strcpy调用替换strdup(分配时不要忘记终止“ \\ 0”)。 这样,互操作器将根据指针生成.NET字符串后释放这些字符串使用的内存。

最有效的另一种方法是手动编组,即在C#结构中声明以下字段:

 public IntPtr name;

在C ++中,更改代码以仅在其中写入c_str()而不进行复制。

在C#中,使用Marshal.PtrToStringAnsi将它们转换为.NET字符串。 但是请注意,如果在完成自定义编组之前C ++会更改所有这些字符串,则应用程序将崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM