-
Sadrazamv4
instagram:sadrazam.spy Tg:Sadrazamv4
🚀 BAŞTAN SONA RUST DİLİ BÖLÜM-19: Unsafe Rust ve FFI (Foreign Function Interface) ☣️
Selamlar! Serimizin 19. bölümüne hoş geldiniz.
Önceki bölümde Rust’ın makro sistemini, `macro_rules!` ile bildirimsel makro yazımını ve Procedural Macros mimarisini detaylarıyla incelemiştik. Bu bölümde ise Rust’ın bellek güvenliği kurallarının bir kısmını devre dışı bırakan **Unsafe Rust** konusunu ve C/C++ gibi dillerle doğrudan iletişim kurmamızı sağlayan **FFI (Foreign Function Interface)** yapısını göreceğiz.
---
☣️ 1. Unsafe Rust Nedir ve Neden İhtiyaç Duyulur? 🛡️🔓
Rust'ın derleyicisi (Borrow Checker) oldukça katıdır. Ancak işletim sistemleri, donanım sürücüleri (drivers), gömülü sistemler veya C kütüphaneleri ile doğrudan çalışırken derleyicinin statik analiz yapamayacağı durumlar oluşur.
İşte bu noktada Rust bize `unsafe` bloğunu sunar.
⚠️ **Kritik Yanılgı:** `unsafe` demek "Borrow Checker kapandı, bellek yönetimi tamamen kontrolsüz" anlamına GELMEZ. Ownership, Lifetimes ve tip denetimleri halen geçerlidir. `unsafe` bloğu size yalnızca 5 özel "süper güç" verir!
#### Unsafe Rust'ın 5 Süper Gücü:
1. Ham işaretçileri (Raw Pointers) dereference etmek (çözmek).
2. `unsafe` fonksiyonları veya metotları çağırmak.
3. Değiştirilebilir statik değişkenleri (`mutable static`) okumak veya değiştirmek.
4. `unsafe` trait'leri uygulamak (implement etmek).
5. `union` alanlarına erişmek.
---
📍 2. Raw Pointers (Ham İşaretçiler: `*const T` ve `*mut T`) 🎯
Rust'taki standart referansların (`&T` ve `&mut T`) aksine, Raw Pointer'lar:
• Aynı anda hem mutable hem immutable olarak aynı adresi gösterebilir.
• `null` veya bozuk (invalid) bellek adreslerini gösterebilir.
• Otomatik bellek temizliği (Drop) mekanizmasına sahip değildir.
• Yaşam süreleri (Lifetimes) derleyici tarafından takip edilmez.
Raw Pointer **oluşturmak** Unsafe DEĞİLDİR; ancak içindeki veriye erişmek (dereference etmek) **UNSAFE**'tir!
fn main() {
let mut sayi = 10;
// Raw Pointer oluşturma (Safe)
let p1 = &sayi as *const i32;
let p2 = &mut sayi as *mut i32;
// Raw Pointer dereferencing (Unsafe!)
unsafe {
println!("p1 değeri: {}", *p1);
println!("p2 değeri: {}", *p2);
*p2 = 20;
println!("Yeni değer: {}", *p2);
}
}
---
⚙️ 3. Unsafe Fonksiyonlar ve Güvenli Soyutlama (Safe Abstraction) 🛠️
Bir fonksiyonun içinde Unsafe işlemler yapılıyorsa ve çağırana belirli şartlar yüklüyorsa `unsafe fn` olarak tanımlanır.
Ancak Rust dünyasındaki en iyi pratik (Best Practice), **Unsafe kodu Safe bir API arkasında soyutlamaktır (Safe Abstraction).**
Örnek: Standart kütüphanedeki `split_at_mut` benzeri güvenli bir fonksiyon yazalım:
use std::slice;
fn guvenli_dilim_bol(dilim: &mut [i32], orta: usize) -> (&mut [i32], &mut [i32]) {
let uz = dilim.len();
let ptr = dilim.as_mut_ptr();
assert!(orta <= uz); // Sınır kontrolü (Safety Check)
unsafe {
(
slice::from_raw_parts_mut(ptr, orta),
slice::from_raw_parts_mut(ptr.add(orta), uz - orta),
)
}
}
fn main() {
let mut v = vec![1, 2, 3, 4, 5, 6];
let (sol, sag) = guvenli_dilim_bol(&mut v, 3);
println!("Sol: {:?}, Sağ: {:?}", sol, sag);
}
---
🌐 4. FFI: C Kütüphaneleri İle İletişim (`extern "C"`) 🔗
Rust, C dili ile ABI (Application Binary Interface) düzeyinde doğrudan uyumludur. C dilinde yazılmış bir fonksiyonu çağırmak veya C'ye Rust fonksiyonu sunmak son derece kolaydır.
### A. C Standart Kütüphanesinden Fonksiyon Çağırmak (Rust -> C):
extern "C" {
// C'deki abs() ve sqrt() fonksiyonlarının bildirimi
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
// C fonksiyon çağrıları doğası gereği UNSAFE'tir
let sonuc = abs(-42);
println!("C abs() sonucu: {}", sonuc);
}
}
### B. C Diline Rust Fonksiyonu Sunmak (C -> Rust):
// #[no_mangle]: Derleyicinin fonksiyon ismini değiştirmesini (mangling) engeller
// extern "C": C çağırma sözleşmesine (calling convention) uyum sağlar
#[no_mangle]
pub extern "C" fn rust_topla(a: i32, b: i32) -> i32 {
a + b
}
---
🚨 5. Mutable Static Değiştirme ve Global Durum ⚠️
Rust'ta immutable `static` değişkenler güvenlidir. Ancak `static mut` (değiştirilebilir global değişkenler) okumak veya yazmak Data Race riski taşıdığı için **UNSAFE**'tir!
static mut SAYAÇ: u32 = 0;
fn sayac_arttir() {
unsafe {
SAYAÇ += 1;
}
}
fn main() {
sayac_arttir();
unsafe {
println!("Sayaç: {}", SAYAÇ);
}
}
> **Öneri:** Multithreaded uygulamalarda `static mut` yerine her zaman Bölüm 16'da gördüğümüz `Atomic` tipleri (`AtomicU32`) veya `Arc<Mutex<T>>` yapılarını tercih edin.
---
📝 Bölüm Özeti ve Gelecek Bölüm 🔮
Bu bölümde Unsafe Rust’ın kullanım amaçlarını, Raw Pointer'ları (`*const T`, `*mut T`), Unsafe kodları Safe API'ler arkasında soyutlama mantığını ve FFI ile C entegrasyonunu öğrendik.
👉 Bölüm 20'de Bizi Ne Bekliyor?
• Serinin Muhteşem Finali: **Baştan Sona Rust Özeti ve Proje Mimarisi** 🏆
• Gerçek hayat projelerinde Best Practice'ler
• Rust ekosistemi, popüler Crate'ler (Serde, Anyhow, Cl
ap, Reqwest)
• Kariyer ve Rust ile Gelecek Yol Haritası
Sorularınızı konu altından iletebilirsiniz. Serimizin FİNAL bölümünde görüşmek üzere! 🦀✨
Selamlar! Serimizin 19. bölümüne hoş geldiniz.
Önceki bölümde Rust’ın makro sistemini, `macro_rules!` ile bildirimsel makro yazımını ve Procedural Macros mimarisini detaylarıyla incelemiştik. Bu bölümde ise Rust’ın bellek güvenliği kurallarının bir kısmını devre dışı bırakan **Unsafe Rust** konusunu ve C/C++ gibi dillerle doğrudan iletişim kurmamızı sağlayan **FFI (Foreign Function Interface)** yapısını göreceğiz.
---
☣️ 1. Unsafe Rust Nedir ve Neden İhtiyaç Duyulur? 🛡️🔓
Rust'ın derleyicisi (Borrow Checker) oldukça katıdır. Ancak işletim sistemleri, donanım sürücüleri (drivers), gömülü sistemler veya C kütüphaneleri ile doğrudan çalışırken derleyicinin statik analiz yapamayacağı durumlar oluşur.
İşte bu noktada Rust bize `unsafe` bloğunu sunar.
⚠️ **Kritik Yanılgı:** `unsafe` demek "Borrow Checker kapandı, bellek yönetimi tamamen kontrolsüz" anlamına GELMEZ. Ownership, Lifetimes ve tip denetimleri halen geçerlidir. `unsafe` bloğu size yalnızca 5 özel "süper güç" verir!
#### Unsafe Rust'ın 5 Süper Gücü:
1. Ham işaretçileri (Raw Pointers) dereference etmek (çözmek).
2. `unsafe` fonksiyonları veya metotları çağırmak.
3. Değiştirilebilir statik değişkenleri (`mutable static`) okumak veya değiştirmek.
4. `unsafe` trait'leri uygulamak (implement etmek).
5. `union` alanlarına erişmek.
---
📍 2. Raw Pointers (Ham İşaretçiler: `*const T` ve `*mut T`) 🎯
Rust'taki standart referansların (`&T` ve `&mut T`) aksine, Raw Pointer'lar:
• Aynı anda hem mutable hem immutable olarak aynı adresi gösterebilir.
• `null` veya bozuk (invalid) bellek adreslerini gösterebilir.
• Otomatik bellek temizliği (Drop) mekanizmasına sahip değildir.
• Yaşam süreleri (Lifetimes) derleyici tarafından takip edilmez.
Raw Pointer **oluşturmak** Unsafe DEĞİLDİR; ancak içindeki veriye erişmek (dereference etmek) **UNSAFE**'tir!
fn main() {
let mut sayi = 10;
// Raw Pointer oluşturma (Safe)
let p1 = &sayi as *const i32;
let p2 = &mut sayi as *mut i32;
// Raw Pointer dereferencing (Unsafe!)
unsafe {
println!("p1 değeri: {}", *p1);
println!("p2 değeri: {}", *p2);
*p2 = 20;
println!("Yeni değer: {}", *p2);
}
}
---
⚙️ 3. Unsafe Fonksiyonlar ve Güvenli Soyutlama (Safe Abstraction) 🛠️
Bir fonksiyonun içinde Unsafe işlemler yapılıyorsa ve çağırana belirli şartlar yüklüyorsa `unsafe fn` olarak tanımlanır.
Ancak Rust dünyasındaki en iyi pratik (Best Practice), **Unsafe kodu Safe bir API arkasında soyutlamaktır (Safe Abstraction).**
Örnek: Standart kütüphanedeki `split_at_mut` benzeri güvenli bir fonksiyon yazalım:
use std::slice;
fn guvenli_dilim_bol(dilim: &mut [i32], orta: usize) -> (&mut [i32], &mut [i32]) {
let uz = dilim.len();
let ptr = dilim.as_mut_ptr();
assert!(orta <= uz); // Sınır kontrolü (Safety Check)
unsafe {
(
slice::from_raw_parts_mut(ptr, orta),
slice::from_raw_parts_mut(ptr.add(orta), uz - orta),
)
}
}
fn main() {
let mut v = vec![1, 2, 3, 4, 5, 6];
let (sol, sag) = guvenli_dilim_bol(&mut v, 3);
println!("Sol: {:?}, Sağ: {:?}", sol, sag);
}
---
🌐 4. FFI: C Kütüphaneleri İle İletişim (`extern "C"`) 🔗
Rust, C dili ile ABI (Application Binary Interface) düzeyinde doğrudan uyumludur. C dilinde yazılmış bir fonksiyonu çağırmak veya C'ye Rust fonksiyonu sunmak son derece kolaydır.
### A. C Standart Kütüphanesinden Fonksiyon Çağırmak (Rust -> C):
extern "C" {
// C'deki abs() ve sqrt() fonksiyonlarının bildirimi
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
// C fonksiyon çağrıları doğası gereği UNSAFE'tir
let sonuc = abs(-42);
println!("C abs() sonucu: {}", sonuc);
}
}
### B. C Diline Rust Fonksiyonu Sunmak (C -> Rust):
// #[no_mangle]: Derleyicinin fonksiyon ismini değiştirmesini (mangling) engeller
// extern "C": C çağırma sözleşmesine (calling convention) uyum sağlar
#[no_mangle]
pub extern "C" fn rust_topla(a: i32, b: i32) -> i32 {
a + b
}
---
🚨 5. Mutable Static Değiştirme ve Global Durum ⚠️
Rust'ta immutable `static` değişkenler güvenlidir. Ancak `static mut` (değiştirilebilir global değişkenler) okumak veya yazmak Data Race riski taşıdığı için **UNSAFE**'tir!
static mut SAYAÇ: u32 = 0;
fn sayac_arttir() {
unsafe {
SAYAÇ += 1;
}
}
fn main() {
sayac_arttir();
unsafe {
println!("Sayaç: {}", SAYAÇ);
}
}
> **Öneri:** Multithreaded uygulamalarda `static mut` yerine her zaman Bölüm 16'da gördüğümüz `Atomic` tipleri (`AtomicU32`) veya `Arc<Mutex<T>>` yapılarını tercih edin.
---
📝 Bölüm Özeti ve Gelecek Bölüm 🔮
Bu bölümde Unsafe Rust’ın kullanım amaçlarını, Raw Pointer'ları (`*const T`, `*mut T`), Unsafe kodları Safe API'ler arkasında soyutlama mantığını ve FFI ile C entegrasyonunu öğrendik.
👉 Bölüm 20'de Bizi Ne Bekliyor?
• Serinin Muhteşem Finali: **Baştan Sona Rust Özeti ve Proje Mimarisi** 🏆
• Gerçek hayat projelerinde Best Practice'ler
• Rust ekosistemi, popüler Crate'ler (Serde, Anyhow, Cl
ap, Reqwest)
• Kariyer ve Rust ile Gelecek Yol Haritası
Sorularınızı konu altından iletebilirsiniz. Serimizin FİNAL bölümünde görüşmek üzere! 🦀✨
🔒 Bu içeriği görmek için giriş yapın