Pointers in C#

C# allows you to declare raw pointers to memory, such pointers can only be declared and manipulated if the project in which they appear has the “Allow unsafe code” option enabled and the code block has the “unsafe” keyword specified.

C# will not allow you to get at the address of a datum if that datum is itself a reference type or if it contains any member fields that are reference types.

Sometimes when you access the address of something you’ll see a compiler error reminding you to used a “fixed” expression in order to access the address. The fixed keyword prevents the memory in which the datum is situated from being moved by the GC. You will get this error even when accessing the address of a value type sometime because although a value type itself is not manipulated by the GC classes in which value type member fields are situated can be.

Fixed actually causes the compiler to declare a fixed pointer – this is an IL concept and means that the GC is prevented from moving the memory containing your datum until the fixed pointer goes out of scope (of the fixed statement block).

using System;

namespace PointerStuff
{
    class Program
    {
        static unsafe void Main(string[] args)
        {
            Information info;

            Information * info_ptr;

            info_ptr = &(info);

            Container container = new Container();

            info_ptr = &(container.info);    // Elicits:  CS0212

            fixed (Information * field_ptr = &(container.info))
            {
                // Do stuff using the pointer.
            }
        }
    }

    public struct Information
    {
        private DateTime date;
        private int      count;
        private double   rate;
        private long     errors;
    }

    public class Container
    {
        public Information info;
    }
}

As you can see above, line 17 elicits an error because the pointer “info_ptr” is not a fixed pointer but an ordinary pointer. The pointer “field_ptr” however IS a fixed pointer by virtue of being declared within the fixed expression (this is why you must declare a pointer in a fixed expression, you can’t refer to another already declared pointer). So you can think of a “fixed” block as a scoped declaration of a fixed pointer so that when the block is no longer active the fixed pointer is released (this is all done under the hood by the CLR).

While the code within the “fixed” block is executing the GC is prevented from moving the managed object “container” declared on line 15.

Examining Memory in Visual Studio

The Visual Studio debugger makes it easy to see raw memory when debugging, this is a useful feature when working with C# pointers.

image

If you comment out line 17 and add the line shown at 23 above, then run the app with a break on line 23 the app will stop at that line. Then if you click Debug->Windows->Memory->Memory 1 you will see a memory dump window. If you then single step and execute line 23 you’ll see the modified bytes in the memory dump (they get highlighted in red). The memory dump window lets you see what gets changed but also where – which bytes – get changed, this is invaluable when working with interop scenarios in which memory might be getting accessed by managed and native code.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s