Using Unsafe Code and Pointers in C#

Introduction

One of the biggest features of the .NET platform is the support for type safety. This means that the Common Language Runtime – the engine of .NET – guarantees that there will not be any type errors  (issues which generally arise because of discrepancy between different data types for an application’s constants, variables and methods).

The benefits of type safety include:

  • Illegal operations are avoided.
  • No wild pointers – a pointer of one type is considered as pointer of other type
  • Avoiding buffer overflow

However, there are certain cases where you need access to code to unsafe code – code for which there is no guarantee of type security, e.g. pointers, or calling native APIs (DLLImport).

Any method, type or code block can be defined as unsafe using the unsafe C# keyword.

To compile the code, we need to use the “/unsafe” compiler flag.

Caveat: Tagging your code as unsafe can result in security risks in your code.

The Pointer Basics

In unsafe code, you can declare a type to be a pointer type.

The declaration is shown below:

type* typename;

For example, to declare a pointer to an int, we would declare it as:

int* ptr_MyVal;

If you want to declare multiple pointer types, we declare them as:

int* ptr_MyVal1, ptr_MyVal2;

Pointers can be declared for:

  • all scalar types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal and bool.
  • Enum types
  • Pointer types (pointers to pointers) (type**) – e.g. int**
  • User-defined structs

Let us take a look at a simple C# application to do some pointer arithmetic.

We will create a pointer and use the pointer to add a number to the pointee.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace PointersDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int valueToBeOperated = 10;
            unsafe
            {
                int* ptr_value = &valueToBeOperated;
                Console.WriteLine("valueToBeOperate = " + valueToBeOperated);
                Console.WriteLine("valueToBeOperate via pointer = " +  *ptr_value);
                *ptr_value += 10;
                Console.WriteLine("valueToBeOperate = " + valueToBeOperated);
                Console.WriteLine("valueToBeOperate via pointer = " + *ptr_value);
            }
 
        }
    }
}

In the above listing, we are declaring a pointer to an int and then using the pointer reference to add 10 and then print the output.

To do this, you will have to do two things.

First, the code, which uses pointers will need to be declared in an unsafe context (see the highlighted section).

Next, we need to declare to the compiler  that we want to compile unsafe code. In Visual Studio, we can do it by changing the Project Properties.

Allow Unsafe Code
Allow Unsafe Code

This signals to the compiler to pass the “/unsafe”  flag to the csc.exe compiler.

The output of the above code is:

valueToBeOperate = 10
valueToBeOperate via pointer = 10
valueToBeOperate = 20
valueToBeOperate via pointer = 20

Next, we can take an advanced look to pointers.

In our second case, we will look at pointers to an array.

When we need pointers to objects in the heap, we need to use the fixed keyword to annotate the pointer, to indicate to the compiler that the objects must be fixed to avoid changing the location the pointer is referencing. This results in the object not moving when memory management operations are done.

// Listing 2- Array pointers

int[] myArray = new int[5] { 1, 2, 3, 4, 5 };

                fixed (int* ptr_array = &myArray[0])

                {

                    int* ptr_ptr = ptr_array; // pointer to a pointer

                    Console.WriteLine("*ptr_array = " + *ptr_array);

                    Console.WriteLine("**ptr_ptr = " + *ptr_ptr);

                    *ptr_array += 10;

                    Console.WriteLine("*ptr_array = " + *ptr_array);

                    Console.WriteLine("**ptr_ptr = " + *ptr_ptr);

                    ptr_ptr++;

                    Console.WriteLine("*ptr_array (does not change) = " + *ptr_array);

                    Console.WriteLine("**ptr_ptr (changes to the next array element) = " + *ptr_ptr);

                }

In the above snippet, we declare a pointer to an array, ptr_array. Notice that we need to decorate it with the fixed keyword (highlighted).

When we add 10 to *ptr_array, we are actually dereferencing to the first element and adding 10.

When we increment ptr_ptr (pointer to the pointer to the array), we are telling the pointer to move to the next array element.

The output of the above snippet is:

*ptr_array = 1
**ptr_ptr = 1
*ptr_array = 11
**ptr_ptr = 11
*ptr_array (does not change) = 11
**ptr_ptr (changes to the next array element) = 2

The complete listing of the above code including a working Visual Studio 2013 project is available at PointersDemo

.

Summary

In this article, we learned about using unsafe code and pointers in C#. I hope you have found this information useful.

About the Author

Vipul Patel is a Program Manager currently working at Amazon Corporation. He has formerly worked at Microsoft in the Lync team and in the .NET team (in the Base Class libraries and the Debugging and Profiling team). He can be reached at vipul.patel@hotmail.com

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read