Layout
In many situations you can simply declare and use a struct without worrying about how it is implemented – specifically how its fields are laid out in memory. If you have to provide structs for consumption by other programs, or use such “foreign” structs, then memory layout matters. What do you think the size of the following struct is?
public struct struct1
{
public byte a; // 1 byte
public int b; // 4 bytes
public short c; // 2 bytes
public byte d; // 1 byte
}
A reasonable answer is 8 bytes, this being the sum of the field sizes. If you actually investigate the size of the struct using:
int size = Marshal.SizeOf(test);
…you will discover (in most cases) that the struct takes 12 bytes. The reason is that most CPUs work best with data stored in sizes larger than a single byte and aligned on particular address boundaries. The Pentium likes data in 16-byte chunks, and likes data to be aligned on address boundaries that are the same size as the data. So for example, a 4-byte integer should be aligned on a 4-byte address boundary, i.e. it should be of the form 4n-1. The exact details aren’t important. What is important is that the compiler will add “padding” bytes to align the data within a struct. You can control the padding explicitly, but notice that some processors throw an exception if you use data that isn’t aligned, and this creates a more complicated problem for .NET Compact users.
To control the layout of a struct you need to use InteropServices, so add:
using System.Runtime.InteropServices;
The struct’s layout is controlled by a StructLayout attribute. For example:
[StructLayout(LayoutKind.Sequential)]
public struct struct1
{
public byte a; // 1 byte
public int b; // 4 bytes
public short c; // 2 bytes
public byte d; // 1 byte
}
…forces the compiler to assign the structure sequentially as listed in the definition, which is what it does by default. Other values of LayoutKind are Auto, which lets the compiler determine the layout, and Explicit, which lets the programmer specify the size of each field. Explicit is often used to create sequential memory layouts with no packing, but in most cases it is simpler to use the Pack field. This tells the compiler exactly how to size and align the data that makes up the fields. For example, if you specify Pack=1 then the struct will be organised so that each field is on a byte boundary and can be read a byte at a time – i.e. no packing is necessary. If you change the definition of the struct to:
[StructLayout(LayoutKind.Sequential,
Pack=1)]
public struct struct1
Read more: VSj