2010-01-01 94 views
5

我有一个C++结构,看起来像这样一个结构:不能封送包含一个工会

struct unmanagedstruct 
{ 
    int    flags; 
    union 
    { 
     int    offset[6]; 
     struct 
     { 
      float   pos[3]; 
      float   q[4]; 
     } posedesc; 
    } u; 
}; 

而且我想整理一下它像这样在C#:

[StructLayout(LayoutKind.Explicit)] 
public class managedstruct { 
    [FieldOffset(0)] 
    public int flags; 

    [FieldOffset(4), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)] 
    public int[] offset; 

    [StructLayout(LayoutKind.Explicit)] 
    public struct posedesc { 
     [FieldOffset(0), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)] 
     public float[] pos; 

     [FieldOffset(12), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)] 
     public float[] q; 
    } 

    [FieldOffset(4)] 
    public posedesc pose; 
} 

然而,当我尝试将数据加载到我的结构中时,只有偏移量数组的前3个元素在那里(数组的长度为3)。我可以证实他们的价值观是正确的 - 但我仍然需要其他3个要素。我做了什么明显错误?

我使用这些功能加载结构:

private static IntPtr addOffset(IntPtr baseAddress, int byteOffset) { 
    switch (IntPtr.Size) { 
     case 4: 
      return new IntPtr(baseAddress.ToInt32() + byteOffset); 
     case 8: 
      return new IntPtr(baseAddress.ToInt64() + byteOffset); 
     default: 
      throw new NotImplementedException(); 
    } 
} 

public static T loadStructData<T>(byte[] data, int byteOffset) { 
    GCHandle pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned); 
    T output = (T)Marshal.PtrToStructure(addOffset(pinnedData.AddrOfPinnedObject(), byteOffset), typeof(T)); 
    pinnedData.Free(); 
    return output; 
} 

加载例如:

managedstruct mystruct = loadStructData<managedstruct>(buffer, 9000); 

让我知道如果你需要更多的信息。

+1

编组代码应该如何知道何时将联合编组为“int []”或“float []”?它应该为每个数组元素选择,还是总是一个或另一个? – 2010-01-01 00:32:55

回答

1

我不是100%确定这一点,但我相信联盟意味着两个成员都使用相同的内存。在C++结构的情况下,int []或posedesc结构。所以结构的大小将是sizeof(int)+ sizeof(posedisc)。意思是,联合并不意味着你将拥有一个int []和一个posedisc,你将拥有共享的内存,这些内存可以是C++中的那些类型中的任何一种,但是只有一种或另一种在受管理的域中。

所以我认为你可能需要两个托管结构,一个有偏移,另一个有posedisc。你可以在你的LoadStruct调用中选择一个或另一个。或者,您可以创建一个字节[]字段,并计算将这些字节转换为所需类型的属性。

0

可能导致问题的原因可能是在C++中,int的大小取决于体系结构。

换句话说,在某些情况下,C++结构中的offset数组实际上可能是64位值的数组。

现在,在您的C#结构中,无论何时使用MarshalAs属性,都不会指定ArraySubType参数。

根据文档,当您省略ArraySubType时,应该根据托管数组的类型对结构进行编组,但可能是因为C++结构中的offset数组没有扩展accros 48个字节,而不是24,正在造成你遇到的问题。

我的建议是尝试改变所有intlong在C++结构,以确保尺寸始终是相同的,而且在所有MarshalAs属性添加ArraySubType参数数组。

+0

“长”的大小也取决于体系结构。我建议'int32_t'或任何其他固定大小的类型'stdint.h'。 – 2012-10-08 15:51:20

0

均田迟到了,但我最好的猜测是,你offset数组被通过pos阵列覆盖时编组到达现场,而这将是参考是被覆盖,而不是实际的元素。因此,offset将始终为3(并尝试GetType就可以了,它应该返回Single[]。这就是你得到的重叠引用)。

因此,无论您是否可以删除q并将pos的大小设置为7,也可以使用fixed数组(尽管我不确定它将如何编组)。