无法封送包含联合的结构
我有一个看起来像这样的 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;
}
但是,当我尝试将数据加载到我的结构中时,只有 offset 数组的前 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);
如果您需要更多信息,请告诉我。
I have a C++ struct that looks like this:
struct unmanagedstruct
{
int flags;
union
{
int offset[6];
struct
{
float pos[3];
float q[4];
} posedesc;
} u;
};
And I'm trying to Marshal it like so in 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;
}
However, when I try loading data into my struct only the first 3 elements of the offset array are there (the array's length is 3). I can confirm that their values are correct - but I still need the other 3 elements. Am I doing something obviously wrong?
I'm using these functions to load the struct:
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;
}
Loading example:
managedstruct mystruct = loadStructData<managedstruct>(buffer, 9000);
Let me know if you need more information.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我对此不是 100% 确定,但我相信联盟意味着两个成员使用相同的内存。对于 C++ 结构,为 int[] 或 posedesc 结构。所以结构体的大小将是 sizeof(int) + sizeof(posedisc)。意思是,Union 并不意味着您将同时拥有 int[] 和posedisc,您将拥有共享内存,这些内存可以是 C++ 领域中的任何一种类型,但在托管领域中只能是其中一种类型。
所以我认为你可能需要两种托管结构,一种具有偏移量,一种具有posedisc。您可以在调用 LoadStruct 时选择其中之一。您可以选择创建一个 byte[] 字段并具有将这些字节转换为所需类型的计算属性。
I'm not 100% sure about this but I believe that the Union means that the same memory is used for both members. In the case of the C++ structure, an int[] or a posedesc structure. So the size of the structure will be sizeof(int) + sizeof(posedisc). Meaning, Union doesn't mean you'll have both an int[] and a posedisc you'll have shared memory that can be either of those types in C++ land but only one or the other in managed land.
So I think you probably need two managed structures, one that has offset and one that has posedisc. You can pick one or the other in your call to LoadStruct. Optionally you could create a byte[] field and have calculated properties that convert those bytes into the desired types.
问题的一个可能原因可能是在 C++ 中,
int
的大小取决于体系结构。换句话说,在某些情况下,C++ 结构中的
offset
数组实际上可能是 64 位值的数组。现在,在 C# 结构中,只要使用
MarshalAs
属性,就无需指定ArraySubType
参数。根据文档,当您省略 ArraySubType 时,该结构应该根据托管数组的类型进行编组,但事实可能是C++ 结构体未扩展到 48 个字节而不是 24 个字节,这导致了您遇到的问题。
我的建议是尝试将 C++ 结构中的所有
int
更改为long
以确保大小始终相同,并添加ArraySubType
> 数组的所有MarshalAs
属性中的参数。A possible cause for problem might be the fact that in C++,
int
has a size that depends on the architecture.In other words, in some circumstances, your
offset
array in the C++ struct may be actually an array of 64 bit values.Now, in your C# struct, whenever you used the
MarshalAs
attribute, you do not specify theArraySubType
parameter.According to the documentation, when you omit
ArraySubType
, the struct is supposed to be marshalled according to the type of the managed array, but maybe the fact that theoffset
array in the C++ struct is not spread accros 48 bytes instead of 24, is causing the problem you encountered.My suggestion would be to try to change all
int
tolong
in the C++ struct to ensure the size is always the same, and also add theArraySubType
parameter in all yourMarshalAs
attributes for arrays.有点晚了,但我最好的猜测是,当编组器到达该字段时,您的
offset
数组会被pos
数组覆盖,并且它将成为 引用 被覆盖,而不是实际的元素。因此,offset
的长度将始终为 3(并尝试对其进行GetType
,它应该返回Single[]
。这就是您得到的结果重叠的参考文献。)因此,您可以删除
q
并将pos
' 大小设置为 7,或者您可以使用fixed
数组(尽管我不确定它是如何实现的)将被编组)。Kinda late to the party, but my best guess is that your
offset
array gets overwritten bypos
array when the marshaller reaches the field, and it will be the reference that gets overwritten, not the actual elements. Therefore,offset
will always be of length 3 (and tryGetType
on it, it should returnSingle[]
. This is what you get for overlapped references.).So either you can delete
q
and setpos
' size to 7, or you can usefixed
arrays (although I'm not sure how it will get marshalled).