All notes
Unsaf

Intro

Unsafe code has the following properties:

Unsafe keyword


unsafe static void FastCopy(byte[] src, byte[] dst, int count)
{
    // Unsafe context: can use pointers here.
}

// pointers can also be used in the parameter list:
unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}

// unsafe block
unsafe
{
    // Unsafe context: can use pointers here.
}

Fixed Size Buffers

MSDN: Fixed Size Buffers.

Before C# 2.0, the following struct would be 8 bytes in size. The pathName array is a reference to the heap-allocated array:


public struct MyArray
{
    public char[] pathName;
    private int reserved;
}

Beginning with C# 2.0, a struct can contain an embedded array.


namespace FixedSizeBuffers
{
    internal unsafe struct MyBuffer
    {
        public fixed char fixedBuffer[128];
    }

    internal unsafe class MyClass
    {
        public MyBuffer myBuffer = default(MyBuffer);
    }

    internal class Program
    {
        static void Main()
        {
            MyClass myC = new MyClass();

            unsafe
            {
                // Pin the buffer to a fixed location in memory.
                fixed (char* charPtr = myC.myBuffer.fixedBuffer)
                {
                    *charPtr = 'A';
                }
            }
        }
    }
}

The size of the 128 element char array is 256 bytes. Fixed size char buffers always take two bytes per character, regardless of the encoding.

Pointer types

MSDN: Pointer types.

In an unsafe context, a type may be a pointer type, a value type, or a reference type.


int* p1, p2, p3;   // Ok
int *p1, *p2, *p3;   // Valid in c, but Invalid in C#!

// Normal pointer to an object.
int[] a = new int[5] {10, 20, 30, 40, 50};
// Must be in unsafe code to use interior pointers.
unsafe
{
    // Must pin object on heap so that it doesn't move while using interior pointers.
    fixed (int* p = &a[0])
    {
        // p is pinned as well as object, so create another pointer to show incrementing it.
        int* p2 = p;
        Console.WriteLine(*p2);
        // Incrementing p2 bumps the pointer by four bytes due to its type ...
        p2 += 1;
        Console.WriteLine(*p2);
        p2 += 1;
        Console.WriteLine(*p2);
        Console.WriteLine("--------");
        Console.WriteLine(*p);
        // Deferencing p and incrementing changes the value of a[0] ...
        *p += 1;
        Console.WriteLine(*p);
        *p += 1;
        Console.WriteLine(*p);
    }
}

Console.WriteLine("--------");
Console.WriteLine(a[0]);
Console.ReadLine();

// Output:
//10
//20
//30
//--------
//10
//11
//12
//--------
//12

Pointer conversion


class ClassConvert
{
    static void Main() 
    {
        int number = 1024;

        unsafe 
        {
            // Convert to byte:
            byte* p = (byte*)&number;

            System.Console.Write("The 4 bytes of the integer:");

            // Display the 4 bytes of the int variable:
            for (int i = 0 ; i < sizeof(int) ; ++i)
            {
                System.Console.Write(" {0:X2}", *p);
                // Increment the pointer:
                p++;
            }
            System.Console.WriteLine();
            System.Console.WriteLine("The value of the integer: {0}", number);

            // Keep the console window open in debug mode.
            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
    }
}
    /* Output:
        The 4 bytes of the integer: 00 04 00 00
        The value of the integer: 1024
    */