C# 封送包含可变长度数组的C结构
我想将带有可变长度数组的C结构封送回C#,但到目前为止,我没有比指向结构表示的指针和指向浮点的指针更好的了 非托管表示:C# 封送包含可变长度数组的C结构,c#,c,arrays,struct,marshalling,C#,C,Arrays,Struct,Marshalling,我想将带有可变长度数组的C结构封送回C#,但到目前为止,我没有比指向结构表示的指针和指向浮点的指针更好的了 非托管表示: typedef float smpl_t; typedef struct { uint_t length; /**< length of buffer */ smpl_t *data; /**< data vector of length ::fvec_t.length */ } fvec_t; 我想要的是一个.NET样式的数组,其
typedef float smpl_t;
typedef struct {
uint_t length; /**< length of buffer */
smpl_t *data; /**< data vector of length ::fvec_t.length */
} fvec_t;
我想要的是一个.NET样式的数组,其中数据
将是float[]
,但是如果我将结构更改为下面的形式,我确实无法在上面的外部函数中获取托管类型的地址、大小或声明指向托管类型的指针
[StructLayout(LayoutKind.Sequential)]
public unsafe struct fvec_t1
{
public uint length;
public float[] data;
}
,不可能按原样封送变长数组,这是正确的还是仍然有办法实现这一点?简短回答
不能将可变长度数组封送为数组,因为在不知道大小的情况下,互操作封送服务无法封送数组元素
但如果您知道尺寸,它将如下所示:
int arr[15]
您将能够像这样封送它:
[MarshalAs(UnmanagedType.LPArray, SizeConst=15)] int[] arr
如果你不知道数组的长度,这就是你想要的
您可以将其转换为intprt并处理inptr,但首先需要创建2个结构
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct fvec_t1
{
public uint whatever;
public int[] data;
}
另一个如下所示:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct fvec_t2{
public uint whatever;
}
创建一个函数来初始化数组,如下所示
private static int[] ReturnIntArray()
{
int [] myInt = new int[30];
for (int i = 0; i < myInt.length; i++)
{
myInt[i] = i + 1;
}
return myInt;
}
实例化第二个结构
fvec_t2 instance1 = new fvec_t2();
instance1.whatever = instance.whatever
为fvec_t2结构动态分配空间,并为数据数组扩展空间
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(fvec_t2)) + Instance.data.Length);
将fvec_t2的现有字段值转移到ptr指向的内存空间
Marshal.StructureToPtr(instance1, ptr, true);
计算应位于fvec_t2末尾的数据数组字段的偏移量
结构
根据偏移量获取数据数组字段的内存地址
IntPtr address = new IntPtr(ptr.ToInt32() + offset);
将数据复制到ptr
Marshal.Copy(instance.data, 0, address, instance.data.Length);
打电话
bool success = dllfunction(ptr);
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
在上述情况下,我肯定会使用SizeParamIndex
[StructLayout(LayoutKind.Sequential)]
public struct fvec_t1
{
uint length;
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] float[] data;
}
祝你好运。我读了,我说你不能那样做:)。如果你不喜欢我的answe,我可以删除它,如果我可以提前知道大小,那么我就不会问这个问题:-)你可以将它转换为intprt并处理inptr,同样,由于我上面提到的原因,你不能使用float[]数据。但我真的不明白你为什么不投票给我的答案:)@Aybe现在检查我的答案希望这会有帮助:dwy你为什么分配
Marshal.SizeOf(typeof(fvec_t2))+Instance.data.Length
int
type不是1字节的长度。通过将数组作为参数传递,可以很容易地做到这一点。你为什么不这么做?你为什么使用不安全的
?你能详细说明一下吗?问题是,当我指定MarshalAs.Struct时,调用可以工作,但返回的结构是垃圾(长度不正确),所以我猜它不能正常工作。因此,目前唯一有效的方法是返回struct指针并手动访问数据中的项。关于不安全语句,我刚刚忘记删除它。不能将数组放在结构中,而让封送拆收器来完成这项工作。但是您可以将数组作为指针传递并对其进行封送处理。我会尝试一下,谢谢。不幸的是,SizeParamIndex
仅适用于直接作为参数传递的数组,而不适用于结构中的数组。“这一定是,”皮达尔真的吗?这很不幸,我很惊讶。根据,在“声明原型”下,您可以在那里使用SizeConst
。
Marshal.Copy(instance.data, 0, address, instance.data.Length);
bool success = dllfunction(ptr);
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
[StructLayout(LayoutKind.Sequential)]
public struct fvec_t1
{
uint length;
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] float[] data;
}