Tutors Corner Moderated forum that should hold answers to the FAQs we have here. If you are new check this forum first for the answer to your question.

Go Back  Xtreme .NET Talk > Knowledge Base > Tutors Corner > C# Unions


Reply
 
Thread Tools Display Modes
  #1  
Old 09-17-2006, 01:15 PM
snarfblam's Avatar
snarfblam snarfblam is online now
Ultimate Contributor

Preferred language:
C#, VB
 
Join Date: Jun 2003
Location: USA
Posts: 2,096
snarfblam will become famous soon enough
Default C# Unions



C++ offers a special kind of type that is not present in C#: a union.

For anyone who is not familiar with unions, here is a quick explanation of how they work and what they're good for.


How They Work
A union is somewhat like a struct. A union definition defines a type. A union type has fields and methods like a struct. The key difference is that a union stores all of its fields in the same memory location, whereas a struct stores each field in a different memory location.


What they are good for
The primary use for a union is to conserve memory. Because the fields are stored in the same memory, generally only one field can be used at a time. Assigning one field changes the values of all fields, possibly to an invalid value. But, because all fields are stored in the same location, the size of the union is the size of the largest field, whereas the size of a struct is, at least, the total of the sizes of all fields.

There is another use for unions too: treating the same binary data as different kinds of values. For instance, we could store an IntPtr in a union and then retrieve the value as a regular Int32. In other words, we can convert and dissect data with a union.


Why Bother?
Nearly any kind of conversion we could make through the use of a union we could make through the use of the Convert and BitConverter classes, so why bother using a union? Because it would be fast. The use of a union would be as an optimization. Although a union can occasionally produce less code than the use of conversion classes, the code tends to be harder to read and must be written with much more care because it can introduce kinds of bugs we aren't used to encountering. They should only be used when you really need the speed.


And Now, For Your Viewing Pleasure
If unions are a feature that is not present in C# then why did you read all that? Because unions are a feature present in the Common Language Runtime, and this feature can be utilized through the use of attributes, specifically the System.Runtime.InteropServices.StructLayoutAttribute and the System.Runtime.InteropServices.FieldOffsetAttribute.

Where C++ uses the union keyword for unions, C# must modify a struct with attributes to produce the same behavior. System.Runtime.InteropServices.StructLayoutAttribute allows us to specify how, in memory, the fields of a struct will be laid out : automatically, sequentially, or explicitly. We are looking for the last of the three.

When we are using an explicit layout, System.Runtime.InteropServices.FieldOffsetAttribute is the attribute that specifies where in memory the field will be. For instance, to view the binary value of a char as an unsigned integer, we could use the following struct:
Code:
[StructLayout(LayoutKind.Explicit)]
public struct CharShortConverter
{
    [FieldOffset(0)]
    public char Char;

    [FieldOffset(0)]
    public ushort UShort;

    // This method is not necessary to use a union, but it is very helpful because
    // otherwise we would have to explicitly initialize all the fields each time
    // we declare a variable of this type.
    public static CharShortConverter GetConverter() {
        CharShortConverter converter;

        converter.Char = ' ';
        converter.UShort = 0;

        return converter;
    }
}
This struct could be used as follows:
Code:
// Get a converter
CharShortConverter converter = CharShortConverter.GetConverter();

// Assign a char to the union, read it back as a UShort, and display the value.
converter.Char = 'x';
MessageBox.Show(converter.UShort.ToString());

It would be much quicker, of course, to write code that used the BitConverter class, and usually much smarter, too. If, however, we had to convert a very large number of chars to ushorts, the use of a union could speed things up quite a bit. Instead of invoking a function we only need to assign a variable and read it back.


Shortcomings
The first shortcoming of this method is clearly visible in the first code listing. Because C# has no understanding of what a union is, it does not understand that assigning a value to one field initializes all fields, and so we must initialize the same memory multiple times to make the compiler happy. To make our lives easier, it is smartest to write a static method that will return an already-initialized variable.

The second shortcoming is that, unlike C++, a C# union can't contain arrays. C# unions can't contain any reference types (reference types are garbage collected and structs are not), and arrays are reference types. This means that where in C++ we could access the bytes of an 64-bit integer by index, in C# we must declare eight fields and access them by name.


A Useful Example
The CharShortConverter isn't particularly useful, although I have a much more useful example, which is actually the reason I investigated unions in C# in the first place: image processing. When using unsafe code or the Marshal class to access raw image (as in the tutorial, Bitmap Manipulation) data it is very handy to have a quick way to access the individual color components of each pixel, and so we have the Pixel struct.
Code:
// Represents a 32-bit ARGB pixel
// Allows pixel data to be accessed much faster than via
// the Color struct or the BitConverter class.
[StructLayout(LayoutKind.Explicit)]
public struct Pixel
{
    // Composite ARGB value
    [FieldOffset(0)] public int ARGB;
    // Color components
    [FieldOffset(3)] public byte A;
    [FieldOffset(2)] public byte R;
    [FieldOffset(1)] public byte G;
    [FieldOffset(0)] public byte B;

    // Method to get an instance of this union
    public static Pixel GetPixel() {
        Pixel result;

        result.A = 0;
        result.R = 0;
        result.G = 0;
        result.B = 0;
        result.ARGB = 0;

        return result;
    }

    // Set this union to represent the specified color
    public void LoadColor(System.Drawing.Color c) {
        ARGB = c.ToArgb();
    }

    // Create a Color struct that represents this union
    public Color ToColor() {
        return Color.FromArgb(ARGB);
    }
}
__________________
e
Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe