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]); // 5Zeigerarithmetik
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 gonePuffer 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 stackvoid* 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]); // 99999Wann 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 perfPraxisbeispiel: 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
unsafeermöglicht rohe Zeiger – im Projekt istAllowUnsafeBlockserforderlich - Die
fixed-Anweisung pinnt verwaltete Objekte, damit die GC sie nicht verschiebt - Zeigerarithmetik verschiebt sich um die Elementgröße, nicht um die Byteanzahl
stackallocreserviert 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>,MemoryMarshalund dieUnsafe-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
- Grundlagen von P/Invoke
- LibraryImport und quellcodegeneriertes P/Invoke
- Unsicherer Code, Zeiger und feste Puffer
- COM-Interop und Runtime Callable Wrappers