Usikker kode, pointere og faste buffere
Brug nøgleordet unsafe, arbejd med pointere, fastlås administreret hukommelse med fixed, og få adgang til buffere med fast størrelse i structs.
Usikker kode, pointere og faste buffere er en gratis C# Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C# Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad er unsafe-kode?
C#'s unsafe-nøgleord åbner for direkte manipulation af hukommelse: rå pointere, pointeraritmetik og buffere med fast størrelse. Det omgår GC'ens sikkerhedsgarantier. Aktivér det med <AllowUnsafeBlocks>true</AllowUnsafeBlocks> i din projektfil.
// 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
}Pointertyper i C#
Pointersyntaksen følger C/C++: T* er en pointer til T. Du kan erklære pointere til unmanaged-værdityper (int, double og strukturer uden referencefelter). Pointere til administrerede typer er ikke tilladt.
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
}
}fixed-sætningen
Administrerede objekter kan flyttes af GC'en. Hvis du vil tage adressen på et administreret objekt, skal du fastlåse det med fixed. GC'en flytter ikke objektet, så længe fixed-blokken varer.
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]); // 5Pointeraritmetik
Du kan lægge heltal til pointere eller trække dem fra. Hvis du lægger 1 til en int*, flyttes den 4 bytes frem (sizeof int). Det er grundlaget for hurtige massehukommelsesoperationer.
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: Stakallokering
stackalloc allokerer en hukommelsesblok på stakken (ikke heapen). Ingen belastning af GC'en og ingen fastlåsning er nødvendig. Det er begrænset til den aktuelle metodes stakramme — hukommelsen frigives automatisk, når metoden returnerer.
// 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 goneBuffere med fast størrelse i strukturer
En buffer med fast størrelse indlejrer et array med fast længde direkte i en struktur — ingen heap-allokering og ingen ekstra pointer. Brug modifikatoren fixed inde i en struktur, der er erklæret i en unsafe-kontekst.
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* og typekonvertering
En void* er en typeløs pointer — nyttig til generiske hukommelsesoperationer. Du skal konvertere den til en pointer med en bestemt type, før du derefererer den. Operatoren sizeof(T) fungerer på unmanaged-typer i en unsafe-kontekst.
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 og Unsafe-klassen
System.Runtime.CompilerServices.Unsafe og System.Runtime.InteropServices.MemoryMarshal tilbyder sikre alternativer uden nøgleordet til mange operationer på lavt niveau. De er kompatible med Span og kan bruges uden nøgleordet unsafe.
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]); // 99999Hvornår du ikke skal bruge unsafe
Brug kun unsafe-kode, når der er et klart behov for ydeevne, og der ikke findes et sikkert alternativ. Hold unsafe-området minimalt — isolér det i private hjælpemetoder eller dedikerede typer. Skriv grundige test, og dokumentér antagelserne.
// 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 perfFra virkeligheden: Parsing af en binær protokol
Unsafe-pointere og buffere med fast størrelse er særligt nyttige ved parsing af binære protokoller, hvor strukturens layout skal matche et wireformat nøjagtigt. Strukturen kan castes direkte fra en bytebuffer uden kopiering.
[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
}Hurtigt tjek
Hvorfor er fixed-sætningen nødvendig, når du tager adressen på et administreret objekt?
Opsummering: Unsafe-kode, pointere og faste buffere
Vigtigste pointer:
- Nøgleordet
unsafeåbner for rå pointere — kræverAllowUnsafeBlocksi projektet fixed-sætningen fastlåser administrerede objekter, så GC'en ikke flytter dem- Pointeraritmetik flytter sig med elementets størrelse, ikke med antallet af bytes
stackallocallokerer på stakken — ingen belastning af GC'en, og hukommelsen frigives, når metoden afsluttes- Buffere med fast størrelse (
fixed byte Payload[N]) indlejrer arrays direkte i strukturer - Foretræk klasserne
Span<T>,MemoryMarshalogUnsafei de fleste scenarier
Lær C# med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 93
- Lektioner
- 346
Ofte stillede spørgsmål
Er lektionen “Usikker kode, pointere og faste buffere” gratis?
Ja — hele teksten til “Usikker kode, pointere og faste buffere” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C# Academy-kurset, skal du opgradere til CoddyKit PRO. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Usikker kode, pointere og faste buffere”?
Brug nøgleordet unsafe, arbejd med pointere, fastlås administreret hukommelse med fixed, og få adgang til buffere med fast størrelse i structs. Du øver dig i C# Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C# Academy?
Der kræves ingen tidligere erfaring. C# Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Usikker kode, pointere og faste buffere”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C# Academy-lektion?
Ja. Alle C# Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Grundlæggende om P/Invoke
- LibraryImport og source-genereret P/Invoke
- Usikker kode, pointere og faste buffere
- COM-interoperabilitet og runtime-callable wrappers