0Pricing
C Academy · Pelajaran

Masalah Keamanan Tipe

Risiko variadik.

Masalah Keamanan Tipe 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.

Variadik melewati pemeriksaan tipe

Fungsi C biasa memeriksa kesesuaian argumen dengan tipe parameter. Argumen variadik melewati pemeriksaan ini sepenuhnya.

Kompilator tidak dapat memverifikasi apa yang Anda teruskan setelah ..., sehingga kesalahan mudah terjadi dan berbahaya.

#include <stdio.h>
#include <stdarg.h>

int add(int n, ...) {
    va_list a; va_start(a, n);
    int s = 0;
    for (int i = 0; i < n; i++) s += va_arg(a, int);
    va_end(a);
    return s;
}

int main(void) {
    printf("%d\n", add(2, 3, 4));
    return 0;
}

Tipe yang salah dalam va_arg

Jika Anda membaca argumen dengan tipe yang salah, hasilnya adalah perilaku tidak terdefinisi.

Meneruskan sebuah int tetapi membacanya sebagai double akan menafsirkan ulang byte yang tidak berkaitan dan menghasilkan data acak atau kerusakan.

#include <stdio.h>
#include <stdarg.h>

int read_int(int n, ...) {
    va_list a; va_start(a, n);
    int v = va_arg(a, int);
    va_end(a);
    return v;
}

int main(void) {
    printf("%d\n", read_int(1, 100));
    return 0;
}

Ketidakcocokan string format

Dalam fungsi bergaya printf, penentu yang salah merupakan bug klasik. printf("%d", 3.14) membaca sebuah double seolah-olah itu adalah int.

Kompilator modern memperingatkan ketidakcocokan literal, tetapi tidak dapat menangkap string format yang dibuat saat program berjalan.

#include <stdio.h>

int main(void) {
    double pi = 3.14;
    printf("%f\n", pi);
    return 0;
}

Kejutan promosi bilangan bulat

Tipe kecil dipromosikan menjadi int di bagian variadik. Jadi, meskipun Anda meneruskan char, Anda harus membacanya kembali sebagai int.

Membacanya sebagai char dengan va_arg(a, char) bersifat tidak terdefinisi.

#include <stdio.h>
#include <stdarg.h>

void show(int n, ...) {
    va_list a; va_start(a, n);
    int c = va_arg(a, int);
    printf("char is %c\n", c);
    va_end(a);
}

int main(void) {
    show(1, 'A');
    return 0;
}

Float menjadi double

Argumen float selalu dipromosikan menjadi double dalam variadik. Anda harus membacanya sebagai double, bukan float.

Ini adalah salah satu kesalahan variadik yang paling umum.

#include <stdio.h>
#include <stdarg.h>

void show(int n, ...) {
    va_list a; va_start(a, n);
    double d = va_arg(a, double);
    printf("%.2f\n", d);
    va_end(a);
}

int main(void) {
    float f = 1.5f;
    show(1, f);
    return 0;
}

Membaca terlalu banyak argumen

Jika kode Anda memanggil va_arg lebih banyak kali daripada jumlah argumen yang diberikan pemanggil, Anda membaca data acak dari tumpukan.

Itulah sebabnya jumlah yang akurat atau penanda akhir sangat penting.

#include <stdio.h>
#include <stdarg.h>

int sum(int n, ...) {
    va_list a; va_start(a, n);
    int s = 0;
    for (int i = 0; i < n; i++) s += va_arg(a, int);
    va_end(a);
    return s;
}

int main(void) {
    printf("%d\n", sum(3, 1, 2, 3));
    return 0;
}

Penanda akhir penunjuk NULL perlu diperhatikan

Menggunakan NULL sebagai penanda akhir berisiko: pada beberapa platform, NULL berupa 0 sebagai int, yang ukurannya berbeda dari penunjuk.

Lakukan konversi tipe secara eksplisit, seperti (char *)NULL, untuk memastikan tipe yang tepat diteruskan.

#include <stdio.h>
#include <stdarg.h>

void print_all(const char *first, ...) {
    va_list a; va_start(a, first);
    const char *s = first;
    while (s) { printf("%s\n", s); s = va_arg(a, const char *); }
    va_end(a);
}

int main(void) {
    print_all("a", "b", (char *)NULL);
    return 0;
}

Atribut format kompilator

GCC dan Clang menyediakan __attribute__((format(printf, 1, 2))) untuk memberi tahu kompilator bahwa fungsi Anda menggunakan pemformatan bergaya printf.

Kompilator kemudian memeriksa string format saat kompilasi dan menemukan banyak bug.

#include <stdio.h>
#include <stdarg.h>

void logf(const char *fmt, ...)
    __attribute__((format(printf, 1, 2)));

void logf(const char *fmt, ...) {
    va_list a; va_start(a, fmt);
    vprintf(fmt, a);
    va_end(a);
}

int main(void) {
    logf("%d items\n", 3);
    return 0;
}

Utamakan alternatif yang lebih aman

Karena variadik rentan terhadap kesalahan, jika memungkinkan utamakan rancangan yang aman terhadap tipe: teruskan array eksplisit, struct, atau parameter tetap.

Gunakan variadik hanya untuk kebutuhan nyata yang mirip printf.

#include <stdio.h>

int sum_array(const int *a, int n) {
    int s = 0;
    for (int i = 0; i < n; i++) s += a[i];
    return s;
}

int main(void) {
    int nums[] = {1, 2, 3, 4};
    printf("%d\n", sum_array(nums, 4));
    return 0;
}

Dokumentasikan kontraknya

Karena kompilator tidak dapat menegakkan tipe variadik, dokumentasi yang jelas menjadi perlindungan Anda.

Nyatakan dengan tepat tipe dan jumlah argumen yang harus diberikan pemanggil, serta cara daftar tersebut berakhir.

#include <stdio.h>
#include <stdarg.h>

/* sum_ints(n, ...): pass exactly n int values */
int sum_ints(int n, ...) {
    va_list a; va_start(a, n);
    int s = 0;
    for (int i = 0; i < n; i++) s += va_arg(a, int);
    va_end(a);
    return s;
}

int main(void) {
    printf("%d\n", sum_ints(2, 5, 5));
    return 0;
}

Melakukan pengujian menyeluruh

Karena bug dapat tersembunyi tanpa terlihat, uji fungsi variadik dengan berbagai jumlah dan tipe argumen.

Kasus batas seperti nol argumen atau jumlah maksimum sering mengungkap kesalahan.

#include <stdio.h>
#include <stdarg.h>

int sum(int n, ...) {
    va_list a; va_start(a, n);
    int s = 0;
    for (int i = 0; i < n; i++) s += va_arg(a, int);
    va_end(a);
    return s;
}

int main(void) {
    printf("%d\n", sum(0));
    printf("%d\n", sum(1, 9));
    return 0;
}

Pemeriksaan singkat

Uji pemahaman Anda tentang risiko tipe variadik.

Ringkasan

Anda telah mempelajari bahaya fungsi variadik:

  • Kompilator tidak memeriksa tipe argumen variadik.
  • Tipe yang salah, jumlah yang salah, dan penanda akhir yang keliru menyebabkan perilaku tidak terdefinisi.
  • Ingat promosi: bilangan bulat kecil menjadi int, dan float menjadi double.
  • Gunakan atribut format kompilator, dokumentasikan kontrak, dan jika memungkinkan pilih alternatif yang aman terhadap tipe.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Masalah Keamanan Tipe” gratis?

Ya — teks lengkap “Masalah Keamanan Tipe” 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 “Masalah Keamanan Tipe”?

Risiko variadik. 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 “Masalah Keamanan Tipe” 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. Makro stdarg
  2. Menulis Fungsi Mirip printf
  3. Masalah Keamanan Tipe
  4. Contoh Praktis
← Kembali ke C Academy