Often Unused Operators: fixed()

This post is inspired by Eric Clippert’s post on References and Pointers.

I think it escapes a lot of C# devs that they have the same pointer abilities as C/C++, or maybe it’s that those features have been intentionally down-played by Microsoft for a reason. As C# devs we’ve come to rely on nice, safe and managed code and GC. That doesn’t mean we can’t cause an out of memory exception or infinite recursion or some other bad thing along the way, but for the most part C# tries to protect us. While I’m not going to cover pointers (something of which I have a fondness for given that my very first college class was “Fundamentals of C”) I do want to go over the fixed() operation.

Fixed is basically telling the GC, “Don’t move me, don’t touch me, don’t GC me, don’t even look at me” which is why fixed can only be used within an unsafe context. It’s important to mention that unsafe means, um, unsafe. When you identify an area of code as unsafe you’re saying, “Hey, I know I’m doing something that could potientially be really bad and all the work MS has done to try and protect me I’m ignoring. I really, really promise to only use smart code here.”

Here’s a bit of code using fixed:

unsafe void FixedExample()
{
    double[] arr = { 0, 1.5, 3, 4.5, 6, 7.5, 9 };
    fixed(double* p1 = &arr[1])
    {
        fixed (double* p2 = &arr[5])
        {
            int diff = (int)(p2 - p1);
            Debug.Print(diff.ToString());
        }
    }
}
unsafe void FixedExample2()
{
    double[] array =  { 0, 1.5, 3, 4.5, 6, 7.5, 9 };
    fixed (double* arr = array)
    {
        double* p1 = &arr[1];
        double* p2 = &arr[3];
        int diff = (int)(p2 - p1);
        Debug.Print(diff.ToString());
    }
}

Basically, fixed allows you to get pointers to managed types which would otherwise be subjected to GC. If you were to work just with pointers and not managed types you can do the above (using stackalloc) without even needing fixed.

unsafe void StackallocExample()
{
    int arraySize = 7;
    double* arr = stackalloc double[arraySize];
    double j = 0;
    for (int i = 0; i < arraySize; i++, j += 1.5)
    {
        arr[i] = j;
    }

    double* p1 = &arr[1];
    double* p2 = &arr[15];
    int diff = (int)(p2 - p1);
    Debug.Print(diff.ToString());
}

but of course the above code is very bad. If you didn't notice, the second pointer points to the 16th element (since we're obviously 0 based) but I only allocated 7 doubles worth of memory. If I were do try and do something with arr[15] (rather then just determine the distance between the two elements) that would be very bad as it wouldn't represent a value I had intended and would just be some random bit of whatever was stored in that memory location. Interestingly enough, if you try the same in the first two examples you'll get a runtime exception.

Thanks,
Brian

Leave a Reply