Rust
FFI wrapper
Bir C kütüphanesi için güvenli bir wrapper yazarsın.
Bitirme görevi: FFI sarmalayıcı
C'nin strtol fonksiyonu bir metni verilen tabanda sayıya çevirir ve okumayı nerede bitirdiğini bir çıkış işaretçisiyle bildirir. Ham arayüz hata yapmaya çok açıktır; görev, onu güvenli bir Rust fonksiyonuyla sarmak:
unsafe extern "C" {
fn strtol(s: *const c_char, son: *mut *mut c_char, taban: c_int) -> c_long;
}
fn sayiya(s: &str, taban: i32) -> Result<i64, String> { .. }
Güvenli arayüzün sorumlulukları: metni CString'e çevirmek (iç boş bayt hatası), işaretçinin ne kadar ilerlediğine bakarak geçersiz karakteri bulmak ve sonucu Rust türleriyle döndürmek.
Güvenli sarmalayıcı
offset_from, aynı ayırmanın içindeki iki işaretçi arasındaki eleman farkını verir:
fn sayiya(s: &str, taban: i32) -> Result<i64, String> {
let c = CString::new(s).map_err(|_| String::from("metinde boş bayt var"))?;
let mut son: *mut c_char = std::ptr::null_mut();
// SAFETY: c geçerli bir C dizesi; son yazılabilir bir işaretçi.
let n = unsafe { strtol(c.as_ptr(), &mut son, taban) };
// SAFETY: strtol son'u c'nin içinde bir yere ayarlar.
let okunan = unsafe { son.cast_const().offset_from(c.as_ptr()) } as usize;
match s[okunan..].chars().next() {
None if okunan > 0 => Ok(n as i64),
None => Err(String::from("boş girdi")),
Some(k) => Err(format!("geçersiz karakter: {k}")),
}
}
Uygulama strtol sarmalayıcı
Yukarıdaki bildirimi ve güvenli sayiya fonksiyonunu yaz. sayiya("ff", 16) ve sayiya("101", 2) sonuçlarını unwrap ile, sayiya("12x", 10) sonucunu {:?} ile boşlukla yazdır.
Örnek çözümü göster
use std::ffi::{c_char, c_int, c_long, CString};
unsafe extern "C" {
fn strtol(s: *const c_char, son: *mut *mut c_char, taban: c_int) -> c_long;
}
fn sayiya(s: &str, taban: i32) -> Result<i64, String> {
let c = CString::new(s).map_err(|_| String::from("metinde boş bayt var"))?;
let mut son: *mut c_char = std::ptr::null_mut();
// SAFETY: c geçerli bir C dizesi; son yazılabilir bir işaretçi.
let n = unsafe { strtol(c.as_ptr(), &mut son, taban) };
// SAFETY: strtol son'u c'nin içinde bir yere ayarlar.
let okunan = unsafe { son.cast_const().offset_from(c.as_ptr()) } as usize;
match s[okunan..].chars().next() {
None if okunan > 0 => Ok(n as i64),
None => Err(String::from("boş girdi")),
Some(k) => Err(format!("geçersiz karakter: {k}")),
}
}
fn main() {
println!("{} {} {:?}", sayiya("ff", 16).unwrap(), sayiya("101", 2).unwrap(), sayiya("12x", 10));
}
Kendini test et
-
<code>strtol("12x", &son, 10)</code> sonrasında <code>son</code> nereyi gösterir?
- Başa
- NULL'a
- "x" karakterine (okumanın durduğu yer)
- Dizenin sonuna
Cevabı göster
"x" karakterine (okumanın durduğu yer) — Fark (son - baş) okunan bayt sayısıdır; metin uzunluğuna eşit değilse geçersiz karakter vardır.
-
Çıkış işaretçisi
let mut son: *mut c_char = std::ptr::____();
let n = unsafe { strtol(c.as_ptr(), &mut son, taban) };
Cevabı göster
let mut son: *mut c_char = std::ptr::null_mut();
let n = unsafe { strtol(c.as_ptr(), &mut son, taban) };
-
Girdi ve sonuç
- ("ff", 16)
- Ok(255)
- ("101", 2)
- Ok(5)
- ("12x", 10)
- geçersiz karakter: x
- ("", 10)
- boş girdi
Sıradaki ders: İleri seviye bölüm sınavı