This is a mirror of official site: http://jasper-net.blogspot.com/

Mastering structs in C#

| Sunday, March 21, 2010
Structs are a fundamental data type in C# and most other modern programming languages. They are inherently simple, but you might be surprised at how fast things can become more complicated. The problems mostly arise when you have to work with structures created in other languages, either saved on disk or when calling functions in DLLs or COM. In this article I’m going to assume that you know what a struct is, how to define one and the basics of using one. I’m also going to assume that you have a rough idea of how to call an API function using p/Invoke, and what marshalling is all about. If you are unsure of any of this the standard documentation will give you the basics. Many of the techniques described in this article can be extended to any data type.
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

Posted via email from jasper22's posterous

0 comments: