我应该怎么做才能将C联合结构转移到C#结构,让它们在内存中具有相同的类型

问题描述 投票:0回答:1

这是我在

C
中的结构:

typedef  struct s1 {
    int i;
    union {
        s2 u1;
        s3 u2;
    }
}

typedef struct s2
{
    int w[10];    
}

typedef struct s3
{
    int w[10];
}

这是我的 C# 代码:

public struct s2
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    int[] w;
}

public struct s3
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    int[] w;
}

[StructLayout(LayoutKind.Explicit)]
public struct s4
{
    [FieldOffset(0)]
    int i;
    [FieldOffset(4)]
    s2 s2;
    [FieldOffset(4)]
    s3 s3;
}

当我使用该结构时,它会抛出一个关于[偏移量 4 处的对象字段未正确对齐或与非对象字段重叠]的错误。

我用一个字节来保存这个地方,然后获取字节指针来转换s2或s3结构体;像这样[字节s3;]; 但用起来太糟糕了。

还有其他方法可以直接指定这个类型吗?

我不知道,我尝试添加属性

UnmanagedType.IUNknown
和其他一些,但它仍然不起作用

c# pinvoke
1个回答
2
投票

这里不能使用数组(引用类型);但是,内联数组(类似于“固定缓冲区”)可以很好地工作:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

Console.WriteLine(Unsafe.SizeOf<s4>());
// ^^^ 44 = 11 integers, as expected

var obj = new s4();
obj.s2[3] = 13;
Console.WriteLine(obj.s3[3]); // 13

[InlineArray(10)]
public struct s2
{
    // this just defines the type for the inline array
    private int w;
}
[InlineArray(10)]
public struct s3
{
    // this just defines the type for the inline array
    private int w;
}
[StructLayout(LayoutKind.Explicit)]
public struct s4
{
    [FieldOffset(0)]
    int i;
    // changed accessibility to test
    [FieldOffset(4)]
    public s2 s2;
    [FieldOffset(4)]
    public s3 s3;
}

但是:老实说,鉴于

s2
s2
具有相同的形状......我真的不确定将它们作为单独的类型 is 在这里有什么意义。只要有单一类型和单一字段似乎就可以了。


如果您不使用 .NET 8 或更高版本;固定缓冲区:

public unsafe struct s2
{
    private fixed int w[10];
    public int this[int index]
    {
        get
        {
            fixed (int* ptr = w)
            {
                return new ReadOnlySpan<int>(ptr, 10)[index];
            }
        }
        set
        {
            fixed (int* ptr = w)
            {
                new Span<int>(ptr, 10)[index] = value;
            }
        }
    }
}
public unsafe struct s3
{
    private fixed int w[10];
    public int this[int index]
    {
        get
        {
            fixed (int* ptr = w)
            {
                return new ReadOnlySpan<int>(ptr, 10)[index];
            }
        }
        set
        {
            fixed (int* ptr = w)
            {
                new Span<int>(ptr, 10)[index] = value;
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.