0Pricing
C# Academy · Lektion

Unsicherer Code, Zeiger und feste Puffer

Verwenden Sie das Schlüsselwort unsafe, arbeiten Sie mit Zeigern, fixieren Sie verwalteten Speicher mit fixed und greifen Sie auf Puffer fester Größe in structs zu.

Unsicherer Code, Zeiger und feste Puffer ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist unsicherer Code

Das Schlüsselwort unsafe von C# ermöglicht die direkte Manipulation des Speichers: rohe Zeiger, Zeigerarithmetik und Puffer fester Größe. Es umgeht die Sicherheitsgarantien der GC. Aktivieren Sie es mit <AllowUnsafeBlocks>true</AllowUnsafeBlocks> in Ihrer Projektdatei.

// Must add to .csproj:
// <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

// Unsafe blocks can appear inside methods:
unsafe
{
    int x = 42;
    int* ptr = &x;          // get address of x
    Console.WriteLine(*ptr); // dereference — prints 42
    *ptr = 100;
    Console.WriteLine(x);    // 100 — x was mutated via pointer
}

Zeigertypen in C#

Die Zeigersyntax entspricht der von C/C++: T* ist ein Zeiger auf T. Sie können Zeiger auf nicht verwaltete Werttypen deklarieren (int, double, Strukturen ohne Referenzfelder). Zeiger auf verwaltete Typen sind nicht zulässig.

unsafe
{
    int    i = 10;
    double d = 3.14;

    int*    ip = &i;
    double* dp = &d;

    // Dereference with *
    Console.WriteLine(*ip); // 10

    // Pointer arithmetic — move to next int in memory
    int[] arr = { 1, 2, 3 };
    fixed (int* p = arr)
    {
        Console.WriteLine(*(p + 0)); // 1
        Console.WriteLine(*(p + 1)); // 2
        Console.WriteLine(*(p + 2)); // 3
    }
}

Die fixed-Anweisung

Verwaltete Objekte können von der GC verschoben werden. Um die Adresse eines verwalteten Objekts zu ermitteln, müssen Sie es mit fixed anheften. Die GC verschiebt das Objekt für die Dauer des fixed-Blocks nicht.

byte[] buffer = new byte[256];

unsafe
{
    fixed (byte* pBuf = buffer)
    {
        // pBuf is valid only inside this block
        // GC won't relocate 'buffer' here
        for (int i = 0; i < buffer.Length; i++)
            pBuf[i] = (byte)i;
    }
    // After 'fixed', GC can move 'buffer' again
}

Console.WriteLine(buffer[5]); // 5

Zeigerarithmetik

Sie können Ganzzahlen zu Zeigern addieren oder von ihnen subtrahieren. Das Addieren von 1 zu einem int* verschiebt ihn um 4 Bytes (sizeof int). Dies bildet die Grundlage für schnelle Operationen auf großen Speicherbereichen.

unsafe
{
    int[] data = { 10, 20, 30, 40, 50 };
    fixed (int* start = data)
    {
        int* p = start;
        long sum = 0;
        for (int i = 0; i < data.Length; i++)
        {
            sum += *p;
            p++;    // advance by sizeof(int) = 4 bytes
        }
        Console.WriteLine(sum); // 150

        // Or with index syntax:
        Console.WriteLine(start[2]); // 30
    }
}

stackalloc: Speicherreservierung auf dem Stack

stackalloc reserviert einen Speicherblock auf dem Stack (nicht auf dem Heap). Dadurch entsteht keine Belastung für die GC und es ist kein Pinning erforderlich. Der Speicher ist auf den Stackframe der aktuellen Methode beschränkt und wird automatisch freigegeben, sobald die Methode zurückkehrt.

// Stack-allocated buffer — zero heap allocation
Span<int> buffer = stackalloc int[128]; // safe Span wrapper
buffer.Fill(0);
buffer[0] = 42;
Console.WriteLine(buffer[0]); // 42

// Or raw pointer form (requires unsafe):
unsafe
{
    int* raw = stackalloc int[128];
    raw[0] = 99;
    Console.WriteLine(raw[0]); // 99
}
// Stack frame popped — memory gone

Puffer fester Größe in Strukturen

Ein fixed-size buffer bettet ein Array fester Länge direkt in eine Struktur ein – ohne Heap-Allokation und ohne zusätzlichen Zeiger. Verwenden Sie den fixed-Modifikator innerhalb einer Struktur, die in einem unsafe-Kontext deklariert ist.

unsafe struct NetworkPacket
{
    public int  Length;
    public byte Command;
    public fixed byte Payload[256]; // 256 bytes inline in the struct
}

unsafe
{
    NetworkPacket pkt;
    pkt.Length  = 10;
    pkt.Command = 0x01;

    // Fill payload inline — no heap allocation
    for (int i = 0; i < 10; i++)
        pkt.Payload[i] = (byte)i;

    Console.WriteLine(pkt.Payload[5]); // 5
}
// sizeof(NetworkPacket) = 4 + 1 + 256 = ~261 bytes on stack

void* und Typumwandlungen

Ein void* ist ein typloser Zeiger und eignet sich für allgemeine Speicheroperationen. Vor der Dereferenzierung müssen Sie ihn in einen typisierten Zeiger umwandeln. Der Operator sizeof(T) funktioniert in einem unsicheren Kontext mit nicht verwalteten Typen.

unsafe
{
    int value = 42;
    void* vp = &value;      // typeless pointer
    int*  ip = (int*)vp;    // cast back to int*
    Console.WriteLine(*ip); // 42

    // sizeof works on unmanaged types
    Console.WriteLine(sizeof(int));    // 4
    Console.WriteLine(sizeof(double)); // 8
    Console.WriteLine(sizeof(long));   // 8
}

MemoryMarshal und die Unsafe-Klasse

System.Runtime.CompilerServices.Unsafe und System.Runtime.InteropServices.MemoryMarshal stellen für viele Low-Level-Operationen sichere Alternativen ohne das Schlüsselwort unsafe bereit. Sie sind mit Span kompatibel.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// Reinterpret a Span<byte> as Span<int> — no copy, no unsafe keyword
byte[] raw = new byte[16];
Span<int> ints = MemoryMarshal.Cast<byte, int>(raw);
ints[0] = 12345678;
Console.WriteLine(ints[0]); // 12345678

// Unsafe.As<,> — reinterpret reference type (advanced)
ref int first = ref MemoryMarshal.GetReference(ints);
Unsafe.Add(ref first, 1) = 99999;
Console.WriteLine(ints[1]); // 99999

Wann Sie unsafe verwenden sollten – und wann nicht

Verwenden Sie unsicheren Code nur, wenn ein eindeutiger Performancebedarf besteht und keine sichere Alternative verfügbar ist. Halten Sie den Bereich mit unsicherem Code klein – kapseln Sie ihn in privaten Hilfsmethoden oder dedizierten Typen. Schreiben Sie umfassende Tests und dokumentieren Sie die Annahmen.

// GOOD: narrow unsafe scope
public static unsafe int SumBytes(ReadOnlySpan<byte> data)
{
    int total = 0;
    fixed (byte* p = data)
    {
        byte* end = p + data.Length;
        for (byte* cur = p; cur < end; cur++)
            total += *cur;
    }
    return total;
}

// BETTER for modern code: use SIMD via Vector<T> or hardware intrinsics
// which stay in managed code but still achieve native-level perf

Praxisbeispiel: Ein Binärprotokoll analysieren

Unsichere Zeiger und Puffer fester Größe sind besonders nützlich beim Analysieren von Binärprotokollen, bei denen das Layout der Struktur exakt dem Wire-Format entsprechen muss. Die Struktur kann direkt aus einem Bytepuffer gecastet werden, ohne Kopien anzulegen.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct MessageHeader
{
    public uint  Magic;        // 4 bytes
    public ushort Version;    // 2 bytes
    public ushort PayloadLen; // 2 bytes
    public fixed byte Id[16]; // 16 bytes GUID inline
}

unsafe ReadOnlySpan<byte> SerializeHeader(MessageHeader hdr)
{
    // Cast struct directly to bytes — zero copy
    return new ReadOnlySpan<byte>(&hdr, sizeof(MessageHeader));
}

unsafe MessageHeader ParseHeader(ReadOnlySpan<byte> buf)
{
    fixed (byte* p = buf)
        return *(MessageHeader*)p; // reinterpret cast
}

Schnelltest

Warum ist die fixed-Anweisung erforderlich, wenn Sie die Adresse eines verwalteten Objekts ermitteln?

Zusammenfassung: Unsicherer Code, Zeiger und Puffer fester Größe

Wichtigste Erkenntnisse:

  • Das Schlüsselwort unsafe ermöglicht rohe Zeiger – im Projekt ist AllowUnsafeBlocks erforderlich
  • Die fixed-Anweisung pinnt verwaltete Objekte, damit die GC sie nicht verschiebt
  • Zeigerarithmetik verschiebt sich um die Elementgröße, nicht um die Byteanzahl
  • stackalloc reserviert Speicher auf dem Stack – keine Belastung für die GC, Freigabe beim Verlassen der Methode
  • Puffer fester Größe (fixed byte Payload[N]) betten Arrays direkt in Strukturen ein
  • Bevorzugen Sie in den meisten Fällen Span<T>, MemoryMarshal und die Unsafe-Klasse

Häufig gestellte Fragen

Ist die Lektion „Unsicherer Code, Zeiger und feste Puffer“ kostenlos?

Ja — der vollständige Text von „Unsicherer Code, Zeiger und feste Puffer“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Unsicherer Code, Zeiger und feste Puffer“?

Verwenden Sie das Schlüsselwort unsafe, arbeiten Sie mit Zeigern, fixieren Sie verwalteten Speicher mit fixed und greifen Sie auf Puffer fester Größe in structs zu. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Unsicherer Code, Zeiger und feste Puffer“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Grundlagen von P/Invoke
  2. LibraryImport und quellcodegeneriertes P/Invoke
  3. Unsicherer Code, Zeiger und feste Puffer
  4. COM-Interop und Runtime Callable Wrappers
← Zurück zu C# Academy