无法封送包含联合的结构

发布于 2024-08-16 04:15:23 字数 1844 浏览 10 评论 0原文

我有一个看起来像这样的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

坦然微笑 2024-08-23 04:15:23

我对此不是 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.

南街女流氓 2024-08-23 04:15:23

问题的一个可能原因可能是在 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 the ArraySubType 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 the offset 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 to long in the C++ struct to ensure the size is always the same, and also add the ArraySubType parameter in all your MarshalAs attributes for arrays.

人疚 2024-08-23 04:15:23

有点晚了,但我最好的猜测是,当编组器到达该字段时,您的 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 by pos 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 try GetType on it, it should return Single[]. This is what you get for overlapped references.).

So either you can delete q and set pos' size to 7, or you can use fixed arrays (although I'm not sure how it will get marshalled).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文