Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The fixed statement prevents the garbage collector (GC) from relocating a movable variable during execution. By pinning the object in the managed heap, it allows developers to safely extract and manipulate an unmanaged pointer to the object’s memory address. Without pinning, the GC’s compaction phase could move the object, rendering the pointer invalid and causing memory corruption.

Execution Context and Rules

  • Unsafe Context: The fixed statement can only be used within an unsafe context.
  • Immutability: The pointer variable declared in the fixed statement is implicitly readonly. It cannot be reassigned to point to a different memory address.
  • Scope: The pinning is strictly scoped. Once execution exits the fixed block (or the enclosing scope for C# 8.0+ declarations), the object is unpinned and becomes eligible for GC relocation.
  • Multiple Declarations: Multiple pointers of the same type can be declared in a single fixed statement. Multiple fixed statements can also be nested.

Syntax and Mechanics

Standard Block Syntax
unsafe
{
    byte[] buffer = new byte[1024];
    
    // Pin the array in memory
    fixed (byte* ptr = buffer)
    {
        // ptr is valid and the array is pinned within this block
        *ptr = 0xFF; 
    }
    // buffer is unpinned here
}
C# 8.0+ Declaration Syntax C# 8.0 introduced a block-less fixed declaration, which pins the variable for the remainder of the enclosing scope, reducing indentation.
unsafe void ProcessBuffer(byte[] buffer)
{
    // Pin the array for the duration of the method scope
    fixed byte* ptr = buffer;
    
    *ptr = 0xFF;
    
    // buffer is implicitly unpinned when the method returns
}

Pinning Strings and Arrays

When pinning managed arrays or strings, the fixed statement bypasses the object header and extracts a pointer directly to the first element or character.
unsafe
{
    string text = "CLR";
    
    // Pins the string object, but ptr points to the first char ('C')
    fixed (char* ptr = text)
    {
        // Pointer arithmetic relies on the contiguous memory of the pinned object
        char secondChar = *(ptr + 1); 
    }
}

Custom Types and GetPinnableReference

Starting with C# 7.3, the fixed statement can operate on any custom type, provided the type implements a GetPinnableReference method. This method must return a ref or ref readonly to an unmanaged type.
public class CustomBuffer
{
    private int[] _data = new int[100];
    
    // Enables the type to be used directly in a fixed statement
    public ref int GetPinnableReference()
    {
        return ref _data[0];
    }
}

unsafe
{
    CustomBuffer buffer = new CustomBuffer();
    
    // Implicitly calls buffer.GetPinnableReference()
    fixed (int* ptr = buffer)
    {
        *ptr = 42;
    }
}
Master C# with Deep Grasping Methodology!Learn More