将结构数组传递到函数作为参数
Passing an array of structs to a function as a parameter
我知道这个问题已经在Stackoverflow中出现了很多时间,并且在我启动此问题时检查了Stackoverflow建议的所有问题后,我将发布此问题。
基本上,我想实现这一目标。大图:将一系列结构从C DLL传递到C#应用程序。这里的捕获是,阵列的大小只能由C DLL确定。现在,我只知道,将OUT参数作为函数参数可以获得从C 到C#的任何数组。是的,我可以将REF传递给C 函数,作为OUT参数,其大小尚不清楚但被初始化为null。但是我不确定这是正确的还是是否有效!另一种方法是,将结构数组作为返回值,我在c#。
中没有找到任何示例。所以我做了什么:将此问题简化为C 问题:
我尝试了一些示例示例将构造数组从函数返回到我的主(),从C DLL到测试C 应用程序。 ->正常工作。因此,作为返回值,一系列结构效果很好。显然,因为在调用我的功能填充数组之前,我不必初始化我的结构数组,以填充数组!
但是,我需要以C#End可行的方式实施它!因此,作为函数的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;
}
评论后,我认为我必须对我的代码发表一些评论。我不确定是否可以在我的代码中使用STL数组,向量或STD :: String,我将将其暴露于C#应用程序。这就是为什么我在这里使用新操作员的原因。下一个可能出现的问题在哪里删除?好吧,我必须有另一个API调用删除才能删除为结构分配的内存。当我的C#应用程序成功收到我返回并处理的所有数据时,它将被调用。那不是问题。但是将数据发送到C#是一个问题,这使我写了此示例C 测试应用程序。
没有大的语法或任何特殊代码要编写以将数据发送到C#。如果在C 中起作用,则必须在C#中工作,如果参数和API被正确导出。这就是为什么我试图使我的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 代码。这些是每个语言的Unicode字符串,知道如何在DLL边界上正确分配/交易。唯一的缺点是它们相对较慢。
另一种更复杂的方法声明您的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 会在完成自定义编组之前更改这些字符串,那么您的应用程序将崩溃。
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 当从函数参数中的临时值调用复制构造函数时
- 如何从"decltype()"获取函数参数的数量<funtion>?
- 如何将lambda作为模板类的成员函数参数
- 模板参数推导失败,函数参数/参数不匹配
- 如何在C++中将迭代器作为函数参数传递
- 将函数参数"const char*"转换为"std::string_view"是
- C++ 如何将数组值解压缩为函数参数
- 主函数参数的属性
- 具有两个间接寻址运算符 (C++) 的函数参数的用途
- "Warning: Comma within array index expression"但逗号分隔函数参数
- 如何定义在用作函数参数时工作的类模板的转换
- 将函数参数完美转发到函数指针:按值传递呢?
- 为什么我不能将引用作为 std::async 的函数参数传递
- 什么..(省略号)作为函数原型中唯一的函数参数,C++?
- 是否可以就地构造一个固定大小的数组作为函数参数?
- 接受模板作为函数参数
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- Arduino 函数参数