3

I have a structure definition as follows:

public struct champ
{
    public uint mem1;
    public byte[] mem2;

    public champ(int x)
    {
        mem1 = x;
        mem2 = new byte[15];
    }
}

After creating an object

champ sample = new champ (2);

Applying Marshal.SizeOf(sample) returns 4+4 = 8 instead of 4 +15. Why?

If it was a class, I can understand that logic because the second member is a pointer occupying 4 bytes which points to the byte array mem2 on the heap. Why is this happening for a struct?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Tyler Durden
  • 1,188
  • 2
  • 19
  • 35
  • 1
    Have a look at the answer of [Hans Passant regarding the same matter](http://stackoverflow.com/questions/3361986/how-to-check-the-number-of-bytes-consumed-by-my-structure). – keenthinker Nov 22 '13 at 15:57
  • Why do you care about what `Marshal.SizeOf()` returns? Are you planning to use this struct in PInvoke? – svick Nov 22 '13 at 16:03

2 Answers2

3

The mem2 field has no MarshalAs attribute and so uses default marshalling. And that is as pointer to the first element.

You probably meant to write:

public struct champ
{
    public uint mem1;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
    public byte[] mem2;

    public champ(int x)  { ... }
}

The size of the struct will be 20 because alignment rules mean that an extra padding byte is added at the end of the struct. That is needed to ensure that the size of the struct is an exact multiple of 4, the size of uint. This ensures that arrays of the struct will properly align mem1.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    +1. Note the size won't be 15+4 == 19 but 20, because of the default StructLayout and byte alignment. – ken2k Nov 22 '13 at 15:55
1
public byte[] mem2

This is a reference to an array that lives elsewhere on the heap.
The size of the reference is always 4 bytes (or 8 bytes in a 64-bit process).

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • So, its the same for a strucutre or a class? I thought struct members are stores on the stack and class mems on the heap – Tyler Durden Nov 22 '13 at 15:52
  • 1
    Array is a reference type. Precisely, `System.Array` is a reference type and all .net arrays derive from this class. – Ondrej Janacek Nov 22 '13 at 15:52
  • 1
    @Tyler Your understanding of where structs are stored is incorrect. What about a struct that is a member of a class? – David Heffernan Nov 22 '13 at 15:53
  • 1
    It doesn't matter that `byte[]` is always a reference in the managed heap, what matters is how is it going to be marshaled, because that's what `Marshal.SizeOf()` returns. – svick Nov 22 '13 at 16:05
  • @OndrejJanacek That's not a good argument. All structs derive from `System.ValueType`, which is a reference type. – svick Nov 22 '13 at 16:05
  • @svick Hah, you got me on that one. Structs are exception. – Ondrej Janacek Nov 22 '13 at 16:14
  • @svick Is `System.ValueType` a reference type? or you mean `System.Object` ? – Sriram Sakthivel Nov 22 '13 at 16:25
  • @SriramSakthivel `System.ValueType` indeed is a reference type. [It's documented as such](http://msdn.microsoft.com/en-us/library/system.valuetype) and you can also verify it by checking the value of `typeof(ValueType).IsValueType`. – svick Nov 22 '13 at 16:30