指向包含浮点数组的结构体的指针

本文关键字:结构体 指针 数组 包含浮 | 更新日期: 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之前

这个构建块向您展示了如何处理固定缓冲区。您可以使用该程序中的代码,并确保正确处理了固定缓冲区。当您移动到更复杂的结构时,如果您有任何问题,您可以确信它们与固定缓冲区代码无关。