Reputation: 9926
I define this struct
public enum E1 : byte
{
A,
B,
C
}
public enum E2 : byte
{
D,
E,
F
}
[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct SomeStruct
{
public Int32 _var1; //4 byte
public E1 _var2; //1 byte(because Pack is 4 this will take 4 byte)
public E2 _var3; //1 byte(because Pack is 4 this will take 4 byte)
public UInt64 _var4; //8 byte
}
Now, because i add the StructLayout attribute with Pack=4 i expect that each of the variable that i define will keep the alignment of data fields to be 4.
So i expect that the
int val = Marshal.SizeOf( typeof( SomeStruct ) );
but i check the code and i found that val is 16
So how it can be ?
Where is my misunderstanding ?
Upvotes: 4
Views: 130
Reputation: 477759
SizeOf
specifies the size in bytes.
Now if we do the math we see that:
Int32
has 32
bits thus 4
bytes.Int64
has 64
bits thus 8
bytes.enum
s are encoded on a byte, thus 1
byte.Together that's 1+1+4+8
thus 14
bytes.
But: most systems don't like to work with bytes: they fetch and store data using words (16 bit), or dwords (32 bit). Since minimizing the data structure would result in operations to cut off data and reinstert it, it is packed with tailing zeros.
If you thus work on such system, the compiler might like to pack data together in chunks of 16
bit (or higher). These are easier: if you for instance want to access an element in an array, it doesn't have to fetch two words into memory because the struct is splitted among the words.
An experiment to demonstrate how the data is packed:
using System.Runtime.InteropServices;
namespace Foo {
public enum E1 : byte
{
A,
B,
C
}
public enum E2 : byte
{
D,
E,
F
}
[StructLayout(LayoutKind.Sequential,Pack=4)]
public struct SomeStruct
{
public int _var1; //4 byte
public byte _var2; //1 byte(because Pack is 4 this will take 4 byte)
public byte _var3; //1 byte(because Pack is 4 this will take 4 byte)
public ulong _var4; //8 byte
public SomeStruct (int var1, byte var2, byte var3, ulong var4) {
this._var1 = var1;
this._var2 = var2;
this._var3 = var3;
this._var4 = var4;
}
}
}
Foo.SomeStruct i = new Foo.SomeStruct(1302,5,17,1425);
Marshal.SizeOf( typeof( Foo.SomeStruct ) );
sizeof(Foo.SomeStruct);
int size = sizeof(Foo.SomeStruct);
byte[] result = new byte[size];
IntPtr buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(i, buffer, false);
Marshal.Copy(buffer, result, 0, size);
results in:
{ 22, 5, 0, 0, 5, 17, 0, 0, 145, 5, 0, 0, 0, 0, 0, 0 }
The struct is thus encoded as:
0 32 40 48 64 128
+----------------+----+----+--------+--------------------------------+
| _var1 | _v2| _v3| ------ | _var4 |
+----------------+----+----+--------+--------------------------------+
If you use int
/uint
to encode the variable, one gets:
{ 22, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 5, 0, 0, 0, 0, 0, 0 }
or:
0 32 64 96 128 192
+--------+--------+--------+--------+----------------+
| _var1 | _var2 | _var3 | ------ | _var4 |
+--------+--------+--------+--------+----------------+
Upvotes: 3