Marshal.OffsetOf 不反映运行时现实?

发布于 2025-01-16 01:49:38 字数 1771 浏览 1 评论 0原文

我想获取非托管结构中字段的偏移量。为此,我使用 Marshal.OffsetOf 方法,并且我意识到结果并不反映与 StructLayout 一起使用的 Packing

举个例子:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
unsafe public struct NETGROUP
{
    public bool Advise;
    public bool Active;
    public int UpdateRate;
    public double DeadBand;
}

namespace MyApp // Note: actual namespace depends on the project name.
{
    internal class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                // Technique 1 (not correct)
                var oA = Marshal.OffsetOf(typeof(NETGROUP), "Advise").ToInt32();//0
                var oB = Marshal.OffsetOf(typeof(NETGROUP), "Active").ToInt32();//4
                var oC = Marshal.OffsetOf(typeof(NETGROUP), "UpdateRate").ToInt32();//8
                var oD = Marshal.OffsetOf(typeof(NETGROUP), "DeadBand").ToInt32();//12

                // Technique 2 (correct)
                NETGROUP ex = new NETGROUP();
                byte* addr = (byte*)&ex;

                var oAa = (byte*)(&ex.Advise) - addr;//0
                var oBb = (byte*)(&ex.Active) - addr;//1
                var oCc = (byte*)(&ex.UpdateRate) - addr;//4
                var oDd = (byte*)(&ex.DeadBand) - addr;//8
            }
        }
    }
}

我需要在泛型中检索此偏移量构造函数,但第二种技术(这是正确的技术)不允许我在不明确指定类型的情况下实现它

public CMember(Type type, string pszName, CType pType, uint uMod = Modifier.TMOD_NON, int nDim = 0) : base(DefineConstants.TOKN_MBR)
{
    m_sName = pszName;
    m_nOffset = Marshal.OffsetOf(type, pszName).ToInt32(); // !!!
    m_pType = pType;
    m_uMod = uMod;
    m_nDim = nDim;
}

你有想法吗?

I would like to get the offset of a field in an unmanaged structure. For this I use the Marshal.OffsetOf method and I realized that the result does not reflect the Packing used with StructLayout

Take this example:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
unsafe public struct NETGROUP
{
    public bool Advise;
    public bool Active;
    public int UpdateRate;
    public double DeadBand;
}

namespace MyApp // Note: actual namespace depends on the project name.
{
    internal class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                // Technique 1 (not correct)
                var oA = Marshal.OffsetOf(typeof(NETGROUP), "Advise").ToInt32();//0
                var oB = Marshal.OffsetOf(typeof(NETGROUP), "Active").ToInt32();//4
                var oC = Marshal.OffsetOf(typeof(NETGROUP), "UpdateRate").ToInt32();//8
                var oD = Marshal.OffsetOf(typeof(NETGROUP), "DeadBand").ToInt32();//12

                // Technique 2 (correct)
                NETGROUP ex = new NETGROUP();
                byte* addr = (byte*)&ex;

                var oAa = (byte*)(&ex.Advise) - addr;//0
                var oBb = (byte*)(&ex.Active) - addr;//1
                var oCc = (byte*)(&ex.UpdateRate) - addr;//4
                var oDd = (byte*)(&ex.DeadBand) - addr;//8
            }
        }
    }
}

I need to retrieve this offset in a generic constructor but the second technique (which is the correct one) does not allow me to achieve it without specifying the type explicitly

public CMember(Type type, string pszName, CType pType, uint uMod = Modifier.TMOD_NON, int nDim = 0) : base(DefineConstants.TOKN_MBR)
{
    m_sName = pszName;
    m_nOffset = Marshal.OffsetOf(type, pszName).ToInt32(); // !!!
    m_pType = pType;
    m_uMod = uMod;
    m_nDim = nDim;
}

Do you have an idea ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

清泪尽 2025-01-23 01:49:38

OffsetOf 仅返回结构的非托管实例的布局

OffsetOf 提供非托管结构布局的偏移量,该偏移量不一定对应于托管结构布局的偏移量。编组结构可以改变布局并改变偏移。

另请参见结构布局

公共语言运行时控制托管内存中类或结构的数据字段的物理布局。但是,如果要将类型传递给非托管代码,则可以使用 StructLayoutAttribute 属性来控制类型的非托管布局。

“ex”是托管实例,因此您可以获得默认布局

The OffsetOf only returns the layout of the unmanaged instances of a struct

OffsetOf provides the offset in terms of the unmanaged structure layout, which does not necessarily correspond to the offset of the managed structure layout. Marshaling the structure can transform the layout and alter the offset.

See also StructLayout

The common language runtime controls the physical layout of the data fields of a class or structure in managed memory. However, if you want to pass the type to unmanaged code, you can use the StructLayoutAttribute attribute to control the unmanaged layout of the type.

'ex' is a managed instance so you get the default layout

变身佩奇 2025-01-23 01:49:38

Marshal.OffsetOf 按预期工作,“问题”是 System.Boolean,它是 非 blittable 类型 且非托管大小为 4:

Console.WriteLine(sizeof(bool)); // 1
Console.WriteLine(Marshal.SizeOf(typeof(bool)));// prints 4

来自 UnmanagedType 枚举文档:

Bool 4 字节布尔值(true != 0,false = 0)。这是Win32 BOOL类型

更改结构以包含 byte 字段而不是 bool 字段会产生预期的输出:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
unsafe public struct NETGROUP
{
    public byte Advise;
    public byte Active;
    ...
}

Console.WriteLine(Marshal.OffsetOf(typeof(NETGROUP), "Advise")); // 0
Console.WriteLine(Marshal.OffsetOf(typeof(NETGROUP), "Active")); // 1

另一种方法是将 bool 编组为 <代码>UnmanagedType.I1:

1 字节有符号整数。您可以使用此成员将布尔值转换为 1 字节、C 风格的 bool (true = 1, false = 0) .

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct NETGROUP
{
    [MarshalAs(UnmanagedType.I1)]
    public byte Advise;
    [MarshalAs(UnmanagedType.I1)]
    public byte Active;
    ...
}

更多信息请参见此处

Marshal.OffsetOf is working as expected, the "issue" is the System.Boolean which is a non-blittable type and has unmanaged size of 4:

Console.WriteLine(sizeof(bool)); // 1
Console.WriteLine(Marshal.SizeOf(typeof(bool)));// prints 4

From UnmanagedType enum docs:

Bool A 4-byte Boolean value (true != 0, false = 0). This is the Win32 BOOL type

Changing struct to contain byte fields instead of bool ones produces the expected output:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
unsafe public struct NETGROUP
{
    public byte Advise;
    public byte Active;
    ...
}

Console.WriteLine(Marshal.OffsetOf(typeof(NETGROUP), "Advise")); // 0
Console.WriteLine(Marshal.OffsetOf(typeof(NETGROUP), "Active")); // 1

Another approach is to marshal bool as UnmanagedType.I1:

A 1-byte signed integer. You can use this member to transform a Boolean value into a 1-byte, C-style bool (true = 1, false = 0).

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct NETGROUP
{
    [MarshalAs(UnmanagedType.I1)]
    public byte Advise;
    [MarshalAs(UnmanagedType.I1)]
    public byte Active;
    ...
}

Some more info here.

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