Skip to content

stackalloc in nested expressions C# 8.0performancecode reduction

Allow a stackalloc expression anywhere an expression is permitted, not just as a direct initializer.

Stackalloc array initializers C# 7.3 let you write stackalloc int[] { 1, 2, 3 }, but only where the compiler could see the expression directly as the initializer of a local. Using a stack buffer as an argument, or picking between two buffers in a conditional, still required a separate local.

C# 8.0 makes stackalloc an ordinary expression. It can now appear as a method argument, in a conditional, inside an object initializer, or anywhere else an expression of type Span<T> or ReadOnlySpan<T> is accepted.

Code ​

csharp
// As an argument
Console.WriteLine(Sum(stackalloc int[] { 1, 2, 3, 4 }));

// Chosen in a conditional
Span<int> buffer = size > 16
    ? stackalloc int[64]
    : stackalloc int[16];

static int Sum(ReadOnlySpan<int> values)
{
    var total = 0;
    foreach (var value in values) total += value;
    return total;
}
csharp
// A named local was required first
Span<int> values = stackalloc int[] { 1, 2, 3, 4 };
Console.WriteLine(Sum(values));

Span<int> buffer;
if (size > 16)
    buffer = stackalloc int[64];
else
    buffer = stackalloc int[16];

Notes ​

  • The stack frame still grows by the largest buffer on any path, so a conditional with two sizes does not save stack space over the bigger one
  • The result is only assignable to Span<T> or ReadOnlySpan<T>; a stackalloc expression cannot be converted to T[]
  • Because it is now an expression, it can be passed to a method that takes a Span<T>, which is the most common use - avoiding a temporary array on the heap
  • A stackalloc inside a loop allocates its stack space once, at method entry, not per iteration
  • The storage is only valid for the lifetime of the current method, so it cannot be returned or captured
  • See Span and ref struct C# 7.2 for why the result cannot escape

More information ​

Powered by Intracia