简体   繁体   English

如何将C数组映射和编组为C#代码

[英]How to map and marshal a C array into a C# code

I am writing C# code that call a C library and something it is not quite clear in my mind. 我正在编写调用C库的C#代码,这在我看来并不是很清楚。

The C function has this signature: C函数有这个签名:

double* DoSomeStuff(double* input,int numberOfElements);

I have mapped the function as: 我已将函数映射为:

[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern  System.IntPtr DoSomeStuff(ref double input, int numberOfElements) ;

The input value is an array, so the C function will expect a contiguous memory layout. 输入值是一个数组,因此C函数将期望连续的内存布局。 I am more familiar with C++ than C#. 我比C#更熟悉C ++。 In C++ I'd used a std::vector to store the data and then I would use the data() method to get the pointer and exchange the information with C code. 在C ++中,我使用std :: vector来存储数据,然后我将使用data()方法获取指针并使用C代码交换信息。 std::vector guarantees a contiguous layout memory. std :: vector保证了连续的布局内存。

Which data structure can I used in C#? 我可以在C#中使用哪种数据结构? Is there anything like std::vector in C#? 在C#中有什么类似std :: vector的东西吗?

I have faced before the same problem for a string (In C++ std::string is just a std::vector with some make up). 我面临着一个字符串的相同问题(在C ++中,std :: string只是一个带有一些化妆的std :: vector)。 And I have solve the problem using: 我用以下方法解决了这个问题:

System.IntPtr stringExample = Marshal.StringToHGlobalAnsi("StringExample"); 

The static function does the job for me. 静态功能为我完成了这项工作。 There is anything like this function for other types? 其他类型有什么类似的功能吗?

I have asked already too many questions, I think the most important one is: what is the best practise to solve this kind of problem? 我已经问了太多问题,我认为最重要的问题是:解决这类问题的最佳做法是什么?

Thanks 谢谢

1) 1)

Define the input as IntPtr: 将输入定义为IntPtr:

[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern  System.IntPtr DoSomeStuff(IntPtr input, int numberOfElements) ;

2) 2)

Create an array in a fixed block, then create an IntPtr from the Pointer and then pass it to DoSomeStuff . 固定块中创建一个数组,然后从指针创建一个IntPtr,然后将其传递给DoSomeStuff

double[] input = new double[20];
IntPtr result = IntPtr.Zero;
fixed(double* d = &input[0])
{
    result = DoSomeStuff(new InptPtr(d), 20);
}

...

Reason for the fixed block is so that GC does not move the array while unmanaged code is populating it. fixed块的原因是,当非托管代码填充时,GC不会移动阵列。

To make your example work you should define the siganture of the extern function as follows: 为了使您的示例工作,您应该定义extern函数的siganture,如下所示:

[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern  System.IntPtr DoSomeStuff([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)], int numberOfElements);

The second (named) parameter of MarshalAs attaribute tells to the marshaller where the size of the array stored. MarshalAs attaribute的第二个(命名)参数告诉编组器存储数组大小的位置。

Regarding the second question, C# has List<Type> class that behaves similary to std:vector<Type> . 关于第二个问题,C#有List<Type>类,其行为类似于std:vector<Type> However, I don't think you can directly provide it to the marshaller. 但是,我不认为你可以直接提供给编组人员。 What you can do is to use ToArray() methor of the List class, to get an array. 你可以做的是使用List类的ToArray()方法来获得一个数组。

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

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