Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

236
Views
Marshal.OffsetOf don't reflect the runtime reality?

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 ?

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

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

over 4 years ago · Santiago Trujillo Report

0

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.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!