Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my struct coming out to an unexpected size when I have a double in it?

Tags:

c#

double

struct

public struct TestStruct
{
    public int first;
    public int second;
    public int third;
}

Marshal.SizeOf returns 12, which is what I assume because the ints are 4 bytes each. If I were to change third to a double instead of an int, I would expect Marshal.SizeOf to return 16. It does. But if I were to add a fourth that was a double, Marshal.SizeOf returns 24, when I expect 20. I could have 10 ints and it would end up each int counted as 4bytes each. But if I add a double in after 3 ints, the size isn't what I expect.

public struct TestStruct //SizeOf 12
{
    public int first;
    public int second;
    public int third;
}  

public struct TestStruct //SizeOf 16
{
    public int first;
    public int second;
    public double third;
}  

public struct TestStruct //SizeOf 24, but I feel like it should be 20
{
    public int first;
    public int second;
    public double third;
    public int fourth;
}

Where has my thinking led me astray?

like image 268
sdouble Avatar asked Aug 23 '12 03:08

sdouble


3 Answers

In addition to JimR's answer, you can explicitly change this behaviour using the StructLayout attribute:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TestStruct // sizeof is now 20
{
    public int first;
    public int second;
    public double third;
    public int fourth;
}

You've told the compiler that this struct is sequentially laid out, and that the packing type should be 1, which means that all fields are laid out directly after each other. Pack 0 (the default) tells the compiler to use the current platforms padding.. while anything else (in multiples of 2) will lay it out in those specific boundaries. I would advise against this though.. it could become unpredictable depending on your usage.

For more info, see this MSDN article: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.pack.aspx

like image 143
Simon Whitehead Avatar answered Nov 12 '22 16:11

Simon Whitehead


You're not considering any padding that is put in the structure.

In some cases it is more efficient for a CPU to read something at a multiple of it's size. For instance, some CPUs like ints aligned on 4 byte boundaries. Some CPUs have to issue 2 reads if an int is not aligned.

int, float and double are especially sensitive to alignment when they might be touched by SSE type instructions on Intel processors.

like image 41
JimR Avatar answered Nov 12 '22 15:11

JimR


I believe the answer lies in the alignment of the data fields.

For example, by default a struct defined with C# is going to have this attribute on it:

[StructLayout(LayoutKind.Sequential)]

If you look at the definition of LayoutKind.Sequential, it states:

LayoutKind Enumeration

The members of the object are laid out sequentially, in the order in which they appear when exported to unmanaged memory. The members are laid out according to the packing specified in StructLayoutAttribute.Pack, and can be noncontiguous.

If you were to specify this attribute instead:

[StructLayout(LayoutKind.Auto)]

You would get the size you expect - 20.

like image 4
James Avatar answered Nov 12 '22 17:11

James