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



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

举个例子:

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;
}

你有主意吗?

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

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

另请参阅结构布局

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

'ex'是一个托管实例,因此您可以获得默认布局

Marshal.OffsetOf按预期工作;发行";是System.Boolean,它是一种非blitable类型,非托管大小为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;
...
}

点击此处了解更多信息。

最新更新