将浮点数组编组到 c#

Ave*_*ius 0 c# c++ marshalling

我正在尝试将包含浮点数组的结构从 C++ DLL 编组到 C#。

我从以下代码创建了 C++ DLL:

//MarshalTest.h
namespace mTest{

    typedef struct {

        float data[3];
        int otherStuff;

    } dataStruct;

    extern "C" __declspec(dllexport) dataStruct getData();
}

//MarshalTest.cpp
#include "MarshallTest.h"

using namespace std;

namespace mTest{
    dataStruct getData(){
        dataStruct d = {{ 16, 2, 77 }, 5};
        return d;
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用以下代码使 getData-Function 在 C# 中可用:

public unsafe struct dataStruct{
    public fixed byte data[3];
    public int otherStuff;

    public unsafe float[] Data{
        get{
            fixed (byte* ptr = data){
                IntPtr ptr2 = (IntPtr)ptr;
                float[] array = new float[3];

                Marshal.Copy(ptr2, array, 0, 3);
                return array;
            }
        }

        set{
            fixed (byte* ptr = data){
                //not needed
            }
        }
    }
}

[DllImport("MarshallTest", CallingConvention = CallingConvention.Cdecl)]
private static extern dataStruct getData ();
Run Code Online (Sandbox Code Playgroud)

在 C# 中打印 data[] 时,我得到以下输出:1.175494E-38 1.610935E-32 8.255635E-20

我究竟做错了什么?

Ron*_*yer 6

我不确定您为什么要进行所有不安全的操作和指针操作。如果你正确定义了你的结构,它非常简单:

[StructLayout(LayoutKind.Sequential)]
public struct dataStruct
{
    [MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]
    public float[] data;
    public int otherStuff;
}
Run Code Online (Sandbox Code Playgroud)

您只需要使用有关您的类型的一些附加信息来指示互操作编组,然后您就可以在不使用不安全构造和指针的情况下获取非托管数据。在 C# 中使用指针的原因非常非常少。

您的可能无法正常工作,因为您使用byte[]数组作为第一个参数,因此当从非托管端复制数据时,您会覆盖大量数据(也许您认为 usingfixed将它们变成指针?)。类型必须匹配,以便结构匹配并正确复制数据。此外,由于 C# 会自动重新排列结构以最适合内存,因此您可能不会像您想象的那样放置数据。这就是StructLayout上面示例顶部的作用,它告诉编译器按顺序保持结构的定义。