从非托管 C DLL 转换混合类型 return 数据?

Converting mixed type return data from an unmanaged C DLL?

我正在编写一个包装器 C# DLL 以与供应商提供的用 C 编写的非托管 DLL 进行交互。在大多数情况下,一切都很顺利,但是在提供的文档中有一些功能如下所示:

int get_value(int unit, int id, int* value)

我的问题是 int* value 是一个混合了 int 和 float 的数组...文档说明哪个是哪个,即第一个值是 int,第二个和第三个是 float,等等。如果我专门将 DLL value 调用为 intfloat,我会取得一些成功。 return 是我正在寻找的一些数据,但仅限于一种类型。例如,这有点有效:

[DllImport("supplier.dll")]
public static extern int get_value(int unit, int id, float* value)

public static int GetValue(int unit, int id, out float[] value)
{
     float[] value = new float[3];
     int ret = get_value(unit, id, value);
     
     return ret;
}

value 用 [NaN, value1, value2] return 编辑,因为 0 索引实际上是一个整数,它没有被正确解释。我试图在非托管 DLL 中使用 IntPtr[] 作为 return value,然后使用 Marshal.Copy() 从内存位置获取数据,但这并不顺利。这是一个有前途的方法吗?如果是这样,我不确定要使用哪个重载,一个例子会很有帮助!

int* value is an array with a mixture of int's and float's...

这严重违反了 strict aliasing rule 并且会 引发未定义的行为 。在 C 中,您必须改用联合。文档应该是这样的

union Value
{
    int i;
    float f;
};

int get_value(int unit, int id, union Value* value);

忽略 supplier.dll C# 中的原始 UB 你可以用 FieldOffset

模拟类似的功能
[StructLayout(LayoutKind.Explicit)] 
public struct Value
{
    [FieldOffset(0)] public int i;
    [FieldOffset(0)] public float f;
}

[DllImport("supplier.dll")]
public static extern int get_value(int unit, int id, out Value[] value);

public static int GetValue(int unit, int id, out Value[] value)
{
     float[] value = new float[3];
     int ret = get_value(unit, id, value);
     
     return ret;
}

获取数组后,使用正确的字段即可得到期望值

var ret = GetValue(unit, id, out Value[] value);
var f0 = value[0].f;
var i1 = value[1].i;

如果你真的想在没有联合的情况下这样做,那么你必须像这样获得浮点数的二进制表示

float f0 = value[0];
int i1 = BitConverter.SingleToInt32Bits(value[1]);
int i2 = BitConverter.SingleToInt32Bits(value[2]);

value[1] = BitConverter.Int32BitsToSingle(f0 + 0.123f);

但是如果数组总是有 3 个这样的项目,那么为什么 return 数组而不是结构?

public struct Values
{
    public float f0;
    public int i1;
    public int i2;
}

[DllImport("supplier.dll")]
public static extern int get_value(int unit, int id, out Values values);

public static int GetValue(int unit, int id, out Values values) {...}