0Pricing
C# Academy · Pelajaran

Kode Tidak Aman, Pointer & Buffer Tetap

Gunakan kata kunci unsafe, bekerja dengan pointer, mengunci memori terkelola menggunakan fixed, dan mengakses buffer berukuran tetap dalam struct.

Kode Tidak Aman, Pointer & Buffer Tetap adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.

Apa Itu Kode Unsafe?

Kata kunci unsafe pada C# memungkinkan manipulasi memori secara langsung: penunjuk mentah, aritmetika penunjuk, dan buffer berukuran tetap. Kata kunci ini melewati jaminan keamanan pengumpul sampah. Aktifkan dengan <AllowUnsafeBlocks>true</AllowUnsafeBlocks> dalam berkas proyek Anda.

// 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
}

Tipe Penunjuk dalam C#

Sintaks penunjuk menyerupai C/C++: T* adalah penunjuk ke T. Anda dapat mendeklarasikan penunjuk ke tipe nilai yang tidak terkelola (int, double, dan struktur tanpa anggota referensi). Penunjuk ke tipe terkelola tidak diperbolehkan.

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
    }
}

Pernyataan fixed

Objek terkelola dapat dipindahkan oleh pengumpul sampah. Untuk mengambil alamat objek terkelola, Anda harus menyematkannya dengan fixed. Pengumpul sampah tidak akan memindahkan objek tersebut selama blok fixed berlangsung.

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

Aritmetika Penunjuk

Anda dapat menambahkan atau mengurangkan bilangan bulat dari penunjuk. Menambahkan 1 ke int* akan memajukannya sebesar 4 byte (ukuran int). Inilah dasar operasi memori massal yang cepat.

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: Alokasi pada Tumpukan

stackalloc mengalokasikan blok memori pada tumpukan, bukan heap. Tidak ada tekanan pada pengumpul sampah dan tidak diperlukan penyematan. Alokasi ini terbatas pada bingkai tumpukan metode saat ini—memori dibebaskan secara otomatis saat metode mengembalikan nilai.

// 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

Buffer Berukuran Tetap dalam Struktur

Buffer berukuran tetap menyematkan larik dengan panjang tetap secara langsung di dalam struktur—tanpa alokasi heap dan tanpa penunjuk tambahan. Gunakan pengubah fixed di dalam struktur yang dideklarasikan dalam konteks unsafe.

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* dan Pengecoran Tipe

void* adalah penunjuk tanpa tipe yang berguna untuk operasi memori umum. Anda harus melakukan pengecoran ke penunjuk bertipe sebelum melakukan dereferensi. Operator sizeof(T) bekerja pada tipe yang tidak terkelola dalam konteks unsafe.

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 dan Kelas Unsafe

System.Runtime.CompilerServices.Unsafe dan System.Runtime.InteropServices.MemoryMarshal menyediakan alternatif aman, tanpa kata kunci, untuk banyak operasi tingkat rendah. Keduanya kompatibel dengan Span dan dapat digunakan tanpa kata kunci 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]); // 99999

Kapan (Tidak) Menggunakan Unsafe

Gunakan kode unsafe hanya jika terdapat kebutuhan kinerja yang jelas dan tidak ada alternatif aman. Minimalkan bagian unsafe—isolasi pada metode pembantu privat atau tipe khusus. Tulis pengujian menyeluruh dan dokumentasikan asumsi yang digunakan.

// 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

Dunia Nyata: Mengurai Protokol Biner

Penunjuk unsafe dan buffer berukuran tetap sangat berguna saat mengurai protokol biner yang tata letak strukturnya harus sama persis dengan format data. Struktur tersebut dapat langsung dikonversi dari buffer byte tanpa penyalinan.

[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
}

Pemeriksaan Singkat

Mengapa pernyataan fixed diperlukan saat mengambil alamat objek terkelola?

Ringkasan: Kode Unsafe, Penunjuk, dan Buffer Tetap

Poin-poin utama:

  • Kata kunci unsafe memungkinkan penggunaan penunjuk mentah—memerlukan AllowUnsafeBlocks dalam proyek
  • Pernyataan fixed menyematkan objek terkelola agar pengumpul sampah tidak memindahkannya
  • Aritmetika penunjuk bertambah berdasarkan ukuran elemen, bukan byte
  • stackalloc mengalokasikan memori pada tumpukan—tanpa tekanan pada pengumpul sampah, dan dibebaskan saat metode selesai
  • Buffer berukuran tetap (fixed byte Payload[N]) menyematkan larik secara langsung di dalam struktur
  • Untuk sebagian besar skenario, lebih baik gunakan kelas Span<T>, MemoryMarshal, dan Unsafe

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Kode Tidak Aman, Pointer & Buffer Tetap” gratis?

Ya — teks lengkap “Kode Tidak Aman, Pointer & Buffer Tetap” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Kode Tidak Aman, Pointer & Buffer Tetap”?

Gunakan kata kunci unsafe, bekerja dengan pointer, mengunci memori terkelola menggunakan fixed, dan mengakses buffer berukuran tetap dalam struct. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai C# Academy?

Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Kode Tidak Aman, Pointer & Buffer Tetap” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?

Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Dasar-Dasar P/Invoke
  2. LibraryImport & P/Invoke yang Dibuat dari Sumber
  3. Kode Tidak Aman, Pointer & Buffer Tetap
  4. Interoperabilitas COM & Runtime Callable Wrapper
← Kembali ke C# Academy