【问题标题】:Size of a pointer field in a struct结构中指针字段的大小
【发布时间】:2017-06-30 21:09:25
【问题描述】:

我必须定义一个使用不安全代码的结构,所以我必须设置每个字段的 FieldOffset 值。但我无法定义指针的大小。这是代码:

[StructLayout(LayoutKind.Explicit)]
public struct SomeStructO
{
    public SomeStructO(int theNumber)
    {
        TheNumber = theNumber;
        Coordinates = PointF.Empty;
        SomeNumbers = null;
    }

    [FieldOffset(0)]
    public PointF Coordinates;

    [FieldOffset(sizeof(float) * 2)]
    public int[] SomeNumbers;

    [FieldOffset(sizeof(float) * 2 + IntPtr.Size)]
    public int TheNumber;
}

给出错误,因为 IntPtr.Size 不是常量表达式 当然这个也不编译:

Marshal.SizeOf(typeof(IntPtr))

归结为问题标题,更多的是如何在 FieldOffset 定义中设置特定的“32bit 64bit compile”指针数据大小。

编辑:我也不能放“public int[] SomeNumbers;”结构末尾的字段,因为我的结构中有 2 个不同的数组.. 比如“public int[] SomeOtherNumbers;”

【问题讨论】:

  • 你有一个更大的问题,你不能编组一个包含数组的结构。除非您使用 UnmanagedType.ByValArray,否则它看起来不像您想要的那样。仅将其声明为 IntPtr 并自己编组数组是一种解决方法。请对照本机声明检查这一点,这很不寻常,因为它是如此令人头疼的内存管理。否则,上述问题的解决方案非常微不足道,根本不要使用 [FieldOffset]。它什么也没做。 LayoutKind.Sequential 已经足够好了。
  • 出于好奇。你为什么给你的结构一个StructLayout 属性?也许还有另一种方法更适合您正在尝试做的事情。
  • 我必须在不安全的块中使用结构,当我不使用 StructLayout 时会出错
  • 你是如何使用 unsafe 块中的结构体的?
  • 实际上我正在研究这个,我还没有弄清楚。我正在尝试 .net 的 PointF 结构,因为它可以在不安全的块中使用,我能够获取数据但无法将一些浮点值直接写入指针浮点地址:(

标签: c# pointers struct sizeof structlayout


【解决方案1】:

我最终在我的项目上放了一个符号,并使用 int 和 long 大小来声明指针大小

[StructLayout(LayoutKind.Explicit, Pack = 2)]
public struct VertexO
{
    public VertexO(Vector location)
    {
        Location = location;
        Neighbours = new IntListO();
        Triangles = new IntListO();
    }
    public VertexO(float x, float y, float z) : this(new Vector(x, y, z)) { }

    [FieldOffset(0)]
    public Vector Location;

    [FieldOffset(sizeof(float) * 3)]
    public IntListO Neighbours;

    #if WIN64
    [FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(long)))]
    #else
    [FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(int)))]
    #endif
    public IntListO Triangles;
}

IntList 是另一个具有 2 个 int 和 1 个指针字段的结构:

    [StructLayout(LayoutKind.Explicit, Pack = 2)]
public struct IntListO
{

    //public IntListO()
    //{
    //    Handle = IntPtr.Zero;
    //    FCount = 0;
    //    SizeOfItem = sizeOfItem;
    //    FCapacity = 0;
    //}

    private static int ItemSize = 4;//size of integer

    [FieldOffset(0)]
    private int FCount;

    [FieldOffset(sizeof(int))]
    private int FCapacity;

    [FieldOffset(sizeof(int) * 2)]
    private IntPtr Handle;
}

所以

#if WIN64
[FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(long)))]
#else
[FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(int)))]
#endif

我实际上能够获得正确的指针大小。

顺便说一句,我使用“Pack = 2”最合理地对齐字节。默认情况下它是 0,当我使用 Marshal.SizeOf(typeof(VertexO)) 时它会增加额外的大小,并且我用一些顶点和三角形测试进行了测试,它工作得很好。

谢谢大家

【讨论】:

    【解决方案2】:

    使用不安全的代码,所以我必须设置每个的 FieldOffset 值 字段

    为什么需要为每个字段指定 FieldOffset?如果您在 StructLayout 属性中使用 LayoutKind.Sequential 和适当的 Pack 大小,则不需要像尝试使用 LayoutKind.Explicit 那样指定确切的 FieldOffset。

    这样的东西可能就是你想要的:

    [StructLayout(LayoutKind.Sequential)]
    public struct SomeStructO
    {
        public SomeStructO(int theNumber)
        {
            TheNumber = theNumber;
            Coordinates = PointF.Empty;
            SomeNumbers = null;
        }
    
        public PointF Coordinates;
    
        [MarshalAs(UnmanagedType.LPArray)]
        public int[] SomeNumbers;
    
        public int TheNumber;
    }
    

    【讨论】:

    • 使用UnmanagedType.LPArray时,还需要指定属性的SizeConstSizeParamIndex字段。另外,值得注意的是,在 C# 中,所有结构默认都有一个连续的StructLayout,因此该属性是多余的。
    • 同意这两点。如果这仅用于 API(托管到非托管),则不必指定 SizeConst,在这种情况下,数组的大小将用于确定要复制和固定的数量;但如果它从非托管代码返回到托管代码,则需要 SizeConst。不确定 OP 将如何使用它,因此最好指出这一点。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    相关资源
    最近更新 更多