The fixed statement prevents the garbage collector from relocating a moveable variable and declares a pointer to that variable. The address of a fixed, or pinned, variable doesn't change during execution of the statement. You can use the declared pointer only inside the corresponding fixed statement. The declared pointer is readonly and can't be modified:
sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedArray
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();
static void PinnedArray()
{
// <PinnedArray>
unsafe
{
byte[] bytes = [1, 2, 3];
fixed (byte* pointerToFirst = bytes)
{
Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
}
}
// Output is similar to:
// The address of the first array element: 2173F80B5C8.
// The value of the first array element: 1.
// </PinnedArray>
}
static void PinnedVariable()
{
// <PinnedVariable>
unsafe
{
int[] numbers = [10, 20, 30];
fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
{
Console.WriteLine(toLast - toFirst); // output: 2
}
}
// </PinnedVariable>
}
static void PinnedSpan()
{
// <PinnedSpan>
unsafe
{
int[] numbers = [10, 20, 30, 40, 50];
Span<int> interior = numbers.AsSpan()[1..^1];
fixed (int* p = interior)
{
for (int i = 0; i < interior.Length; i++)
{
Console.Write(p[i]);
}
// output: 203040
}
}
// </PinnedSpan>
Console.WriteLine();
}
static void PinnedString()
{
// <PinnedString>
unsafe
{
var message = "Hello!";
fixed (char* p = message)
{
Console.WriteLine(*p); // output: H
}
}
// </PinnedString>
}ms.custom: "updateeachrelease"
The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.
The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.
- With an array, as the example at the beginning of this article shows. The initialized pointer contains the address of the first array element.
- With an address of a variable. Use the address-of
&operator, as the following example shows:
sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedVariable
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();
static void PinnedArray()
{
// <PinnedArray>
unsafe
{
byte[] bytes = [1, 2, 3];
fixed (byte* pointerToFirst = bytes)
{
Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
}
}
// Output is similar to:
// The address of the first array element: 2173F80B5C8.
// The value of the first array element: 1.
// </PinnedArray>
}
static void PinnedVariable()
{
// <PinnedVariable>
unsafe
{
int[] numbers = [10, 20, 30];
fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
{
Console.WriteLine(toLast - toFirst); // output: 2
}
}
// </PinnedVariable>
}
static void PinnedSpan()
{
// <PinnedSpan>
unsafe
{
int[] numbers = [10, 20, 30, 40, 50];
Span<int> interior = numbers.AsSpan()[1..^1];
fixed (int* p = interior)
{
for (int i = 0; i < interior.Length; i++)
{
Console.Write(p[i]);
}
// output: 203040
}
}
// </PinnedSpan>
Console.WriteLine();
}
static void PinnedString()
{
// <PinnedString>
unsafe
{
var message = "Hello!";
fixed (char* p = message)
{
Console.WriteLine(*p); // output: H
}
}
// </PinnedString>
}Object fields are another example of moveable variables that you can pin.
When the initialized pointer contains the address of an object field or an array element, the fixed statement guarantees that the garbage collector doesn't relocate or dispose of the containing object instance during the execution of the statement body.
- With the instance of the type that implements a method named
GetPinnableReference. That method must return arefvariable of an unmanaged type. The .NET types System.Span and System.ReadOnlySpan make use of this pattern. You can pin span instances, as the following example shows:
sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedSpan
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();
static void PinnedArray()
{
// <PinnedArray>
unsafe
{
byte[] bytes = [1, 2, 3];
fixed (byte* pointerToFirst = bytes)
{
Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
}
}
// Output is similar to:
// The address of the first array element: 2173F80B5C8.
// The value of the first array element: 1.
// </PinnedArray>
}
static void PinnedVariable()
{
// <PinnedVariable>
unsafe
{
int[] numbers = [10, 20, 30];
fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
{
Console.WriteLine(toLast - toFirst); // output: 2
}
}
// </PinnedVariable>
}
static void PinnedSpan()
{
// <PinnedSpan>
unsafe
{
int[] numbers = [10, 20, 30, 40, 50];
Span<int> interior = numbers.AsSpan()[1..^1];
fixed (int* p = interior)
{
for (int i = 0; i < interior.Length; i++)
{
Console.Write(p[i]);
}
// output: 203040
}
}
// </PinnedSpan>
Console.WriteLine();
}
static void PinnedString()
{
// <PinnedString>
unsafe
{
var message = "Hello!";
fixed (char* p = message)
{
Console.WriteLine(*p); // output: H
}
}
// </PinnedString>
}For more information, see the System.Span.GetPinnableReference API reference.
- With a string, as the following example shows:
sample · csharpdocs/csharp/language-reference/statements/snippets/fixed/Program.csPinnedString
PinnedArray();
PinnedVariable();
PinnedSpan();
PinnedString();
static void PinnedArray()
{
// <PinnedArray>
unsafe
{
byte[] bytes = [1, 2, 3];
fixed (byte* pointerToFirst = bytes)
{
Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
}
}
// Output is similar to:
// The address of the first array element: 2173F80B5C8.
// The value of the first array element: 1.
// </PinnedArray>
}
static void PinnedVariable()
{
// <PinnedVariable>
unsafe
{
int[] numbers = [10, 20, 30];
fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
{
Console.WriteLine(toLast - toFirst); // output: 2
}
}
// </PinnedVariable>
}
static void PinnedSpan()
{
// <PinnedSpan>
unsafe
{
int[] numbers = [10, 20, 30, 40, 50];
Span<int> interior = numbers.AsSpan()[1..^1];
fixed (int* p = interior)
{
for (int i = 0; i < interior.Length; i++)
{
Console.Write(p[i]);
}
// output: 203040
}
}
// </PinnedSpan>
Console.WriteLine();
}
static void PinnedString()
{
// <PinnedString>
unsafe
{
var message = "Hello!";
fixed (char* p = message)
{
Console.WriteLine(*p); // output: H
}
}
// </PinnedString>
}- With a fixed-size buffer.
You can allocate memory on the stack, where it's not subject to garbage collection and therefore doesn't need to be pinned. To do that, use a stackalloc expression.
You can also use the fixed keyword to declare a fixed-size buffer.
C# language specification
For more information, see the following sections of the C# language specification: