CodeBlanks Logo Icon CodeBlanks

Callback

C'den Rust'a callback geçirmeyi öğrenirsin.

Callback

Bazı C fonksiyonları parametre olarak bir fonksiyon işaretçisi alır. Rust tarafında bu işaretçinin türü extern "C" fn(..) -> ..'dir ve gösterdiği fonksiyon C çağrı kuralıyla tanımlanmalıdır. Klasik örnek C'nin qsort'udur:

use std::ffi::{c_int, c_void};

unsafe extern "C" {
    fn qsort(
        taban: *mut c_void,
        adet: usize,
        boyut: usize,
        karsilastir: extern "C" fn(*const c_void, *const c_void) -> c_int,
    );
}

Karşılaştırma fonksiyonu

Callback, aldığı void işaretçilerini bildiği türe çevirir ve C sözleşmesine göre negatif, sıfır ya da pozitif döndürür:

extern "C" fn kucukten_buyuge(a: *const c_void, b: *const c_void) -> c_int {
    // SAFETY: qsort yalnızca dizideki i32 elemanlarının adreslerini verir.
    let (x, y) = unsafe { (*(a as *const i32), *(b as *const i32)) };
    x.cmp(&y) as c_int
}

Ordering'in ayırt edici değerleri -1, 0 ve 1'dir; as c_int bu yüzden doğrudan C'nin beklediği değeri verir.

Uygulama qsort ile sırala

Yukarıdaki qsort bildirimi ve kucukten_buyuge callback'i ile let mut v = [5, 2, 9, 1]; dizisini sırala (v.as_mut_ptr() as *mut c_void, v.len(), size_of::<i32>()) ve {:?} ile yazdır.

Başlangıç kodu

main.rs
use std::ffi::{c_int, c_void};

fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
use std::ffi::{c_int, c_void};

unsafe extern "C" {
    fn qsort(
        taban: *mut c_void,
        adet: usize,
        boyut: usize,
        karsilastir: extern "C" fn(*const c_void, *const c_void) -> c_int,
    );
}

extern "C" fn kucukten_buyuge(a: *const c_void, b: *const c_void) -> c_int {
    // SAFETY: qsort yalnızca dizideki i32 elemanlarının adreslerini verir.
    let (x, y) = unsafe { (*(a as *const i32), *(b as *const i32)) };
    x.cmp(&y) as c_int
}

fn main() {
    let mut v = [5, 2, 9, 1];
    // SAFETY: işaretçi, adet ve boyut v ile tutarlıdır.
    unsafe {
        qsort(v.as_mut_ptr() as *mut c_void, v.len(), std::mem::size_of::<i32>(), kucukten_buyuge);
    }
    println!("{:?}", v);
}

Beklenen çıktı

[1, 2, 5, 9]

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Callback içinde panic olursa ne olur?

  • Görmezden gelinir
  • Rust'a döner
  • C sınırını geçemez; program durdurulur (abort) Doğru cevap
  • C'ye hata döner

Açıklama: extern "C" fonksiyonlarda panic'in yığını C kodundan geri sarması tanımsızdı; artık sınırda abort edilir. Callback'te catch_unwind kullanılabilir.

2 C çağrı kuralı

Soru
____ fn kucukten_buyuge(a: *const c_void, b: *const c_void) -> c_int {
    0
}
Cevap
extern "C" fn kucukten_buyuge(a: *const c_void, b: *const c_void) -> c_int {
    0
}

Açıklama: C'ye verilecek callback C çağrı kuralıyla tanımlanır.

3 Öğe ve anlamı

Kavram Anlamı
extern "C" fn(..) C fonksiyon işaretçisi
*const c_void Türsüz işaretçi
x.cmp(&y) as c_int -1, 0, 1
size_of::<i32>() Eleman boyutu

İleri seviye bölümündeki tüm dersler