指向包含浮点数组的结构体的指针
本文关键字:结构体 指针 数组 包含浮 | 更新日期: 2023-09-27 17:52:42
我正在尝试调用C库用于Xamarin android应用程序。
考虑以下C结构:
typedef struct
{
bool myBool;
myOtherStruct sOtherStruct;
int myInt;
float myFloat;
float myFloatArray[1024];
float myFloatArray2[1024];
float myFloatArray3[20];
float myFloatArray4[30];
} sMyStruct;
使用以下函数调用:
unsigned int initialise(sMyStruct* a_pMyStruct)
我把它放入c#结构中:
[StructLayout(LayoutKind.Sequential)]
public unsafe struct SMyStruct
{
bool myBool;
myOtherStruct sOtherStruct;
int myInt;
float myFloat;
public fixed float myFloatArray[1024];
public fixed float myFloatArray2[1024];
public fixed float myFloatArray3[20];
public fixed float myFloatArray4[30];
public unsafe float[] MyFloatArray
{
get
{
fixed (float* ptr = myFloatArray)
{
float[] array = new float[1024];
Marshal.Copy((IntPtr)ptr, array, 0, 1024 * sizeof(float));
return array;
}
}
}
public SMyStruct (bool MyBool, myOtherStruct otherStruct, int MyInt, float MyFloat)
{
myBool = MyBool;
sOtherStruct = myOtherStruct;
myInt = MyInt;
myFloat = MyFloat;
}
这是我在c#中调用这个的函数:
[DllImport("libMylib")]
private static extern unsafe uint initialise(SMyStruct* a_pMyStruct);
然后我调用这个函数:
public unsafe void init ()
{
SMyStruct initStruct;
uint result = initialise(&initStruct);
}
所以发生的是C函数将返回我的结构与大量的数据。然后,我再次将该结构传递给另一个C例程,该例程在程序的其余部分使用这些参数。
我的问题是我如何得到浮点数组数据回到正确的结构变量,以便我可以再次传递它?目前我的代码是基于这些问题:将浮点数组编组为c#和将复杂结构编组到c#
但是我没有设法编码,所以我可以传递浮点数组回到我的结构,甚至没有看到编译器错误(更不用说失败,当我测试它!)
我如何得到浮点数组数据到我的结构?
编辑经过几个回答和评论,我添加了我最初所做的,试图增加一些清晰度。
我得到一个编译器错误,而不是使用上面的"公共不安全的float[]…"例程我这样做(在结构内):
public SMyStruct (bool MyBool, myOtherStruct otherStruct, int MyInt, float MyFloat, float* MyFloatArray, float* MyFloatArray2, float* MyFloatArray3, float* MyFloatArray4)
{
myBool = MyBool;
sOtherStruct = myOtherStruct;
myInt = MyInt;
myFloat = MyFloat;
myFloatArray = MyFloatArray;
myFloatArray2 = MyFloatArray2;
myFloatArray3 = MyFloatArray3;
myFloatArray4 = MyFloatArray4;
}
使用此代码,我得到错误"您不能使用包含在非固定表达式中的固定大小的缓冲区"。尝试使用固定语句"此时,我尝试使用复制例程。
我想要的是确保字段myFloatArray, myFloatArray2等填充与任何初始化函数返回。仅供参考myBool, sOtherStruct等按我的期望填充。
如果不需要访问数据,可以将其保留为指针。虽然看起来您需要对内存负责,但您需要分配并稍后释放您正在使用的非托管内存。类似…
[DllImport("libMylib")]
private static extern uint initialise(IntPtr a_pMyStruct);
[DllImport("libMylib")]
private static extern uint anotherNativeMethod(IntPtr a_pMyStruct);
//...
//How big is myOtherStruct??
int size = 1 + ?? + 4 + 4 + (1024*4) + (1024*4) + (20*4) + (30*4);
//int size = Marhsal.SizeOf(SMyStruct);
IntPtr pMyStruct = Marshal.AllocHGlobal(size);
initialise(pMyStruct);
anotherNativeMethod(pMyStruct);
Marshal.FreeHGlobal(pMyStruct);
请注意,您仍然可以使用get the Marshaller来使用Marshal.PtrToStructure
将指针复制到您的结构中,但您不再需要在代码中依赖它。
我怀疑你的许多问题都是由于你在不会走之前就试图跑造成的。您试图创建一个包含许多成员的复杂结构体。在一个地方犯了一个错误,任何地方都行不通。
那么,我们如何简化呢?你问的问题和固定缓冲有关。转述你所问的问题:
如何将数组复制到固定缓冲区?
让我们通过使用一个只包含固定缓冲区的简化类型来处理这个问题,并证明我们可以从该缓冲区进行复制。
你的属性getter写对了。最大的问题是你传递了一个不正确的长度。您正在调用的Marshal.Copy
重载的最后一个参数是元素的数量。您错误地传递了字节数。setter在本质上与getter非常相似。它看起来像这样:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
public unsafe struct MyStruct
{
private const int floatArrayLength = 4;
private fixed float _floatArray[floatArrayLength];
public float[] floatArray
{
get
{
float[] result = new float[floatArrayLength];
fixed (float* ptr = _floatArray)
{
Marshal.Copy((IntPtr)ptr, result, 0, floatArrayLength);
}
return result;
}
set
{
int length = Math.Min(floatArrayLength, value.Length);
fixed (float* ptr = _floatArray)
{
Marshal.Copy(value, 0, (IntPtr)ptr, length);
for (int i = length; i < floatArrayLength; i++)
ptr[i] = 0;
}
}
}
}
class Program
{
static void WriteArray(float[] arr)
{
foreach (float value in arr)
{
Console.Write(value);
Console.Write(" ");
}
Console.WriteLine();
}
static void Main(string[] args)
{
MyStruct myStruct = new MyStruct();
WriteArray(myStruct.floatArray);
myStruct.floatArray = new float[] { 1, 2, 3, 4 };
WriteArray(myStruct.floatArray);
myStruct.floatArray = new float[] { 5, 6 };
WriteArray(myStruct.floatArray);
Console.ReadLine();
}
}
}
程序的输出是:
<>之前0 0 0 01 2 3 45 6 0 0之前这个构建块向您展示了如何处理固定缓冲区。您可以使用该程序中的代码,并确保正确处理了固定缓冲区。当您移动到更复杂的结构时,如果您有任何问题,您可以确信它们与固定缓冲区代码无关。