Gömülü Sistemler Açısından C++ ve Rust Üzerine Gözlemler

Son yıllarda yazılım sektöründe en çok konuşulan konulardan biri Rust programlama dilinin bellek güvenliği (memory safety) vaadiyle C ve C++’ın yerini alıp alamayacağıdır. Özellikle Linux çekirdeğine Rust desteğinin girmesiyle bu tartışmalar gömülü yazılım alanına da sıçradı.

Yıllardır C++ ile gömülü Linux (Orange Pi, Raspberry Pi) ve mikrodenetleyiciler (ESP32, STM32) üzerinde çalışan bir mühendis olarak, Rust ekosistemini de belirli projelerde deneyimleme fırsatım oldu. Bu yazıda; internetteki abartılı övgülerden veya dogmatik savunmalardan uzak, gömülü donanım sahasındaki pratik gerçeklikler üzerinden kişisel gözlemlerimi aktarıyorum.


1. Rust’ın Açık ve İnkar Edilemez Avantajları

Rust’ın sahiplik (Ownership) ve borçlanma (Borrowing) modeli gömülü dünyada gerçek bir sorunu çözer:

  • Derleme Zamanında Eşzamanlılık Güvenliği: Çok çekirdekli sistemlerde (örneğin ESP32 dual-core veya Cortex-A serisi) veri yarışları (data races) çalışma anında değil, doğrudan derleyicinin reddetmesiyle önlenir.
  • Standart Paket Yöneticisi (Cargo): C++ dünyasında CMake, Makefile, vcpkg ve Conan arasında parçalanmış yapıya kıyasla Cargo’nun tek tip ve öngörülebilir olması büyük bir konfordur.
  • Option ve Result Tipleri: İstisna mekanizmalarının (try-catch) gömülü sistemlerde kod boyutunu şişirdiği ve öngörülemez gecikmeler yarattığı bilinir. Rust’ın sıfır maliyetli cebirsel veri tipleriyle hata yönetimi son derece zariftir.

2. Gömülü Sahada Karşılaşılan Pratik Zorluklar

Kağıt üzerindeki bu avantajlara rağmen, gerçek bir donanım projesinde Rust’ı ana omurga yapmak henüz her senaryoda kolay değildir:

A. Üretici SDK’leri ve C Kütüphaneleri (C-Interoperability)

Donanım üreticilerinin (Espressif, STMicroelectronics, Microchip, NXP) sağladığı resmi SDK’lerin ve çevre birimi sürücülerinin (HAL) neredeyse tamamı saf C dilinde yazılmıştır.

  • Rust ile bir ESP32 projesi geliştirmek istediğinizde, arka planda yine ESP-IDF C kodlarına bağlanan (bindings/wrapper) katmanları kullanmak zorunda kalırsınız (esp-idf-sys, esp-idf-hal).
  • Bu sarmalayıcı katmanlar (unsafe blokları) arttıkça, Rust’ın sunduğu teorik bellek güvenliği garantisi pratikte üreticinin C kodunun kararlılığına bağımlı hale gelir.

B. Donanım Yazmaçlarına Doğrudan Erişim ve unsafe

Mikrodenetleyici programlarken donanım kesmeleri (Interrupts), DMA arabellekleri ve bellek eşlemeli yazmaçlar (MMIO) ile çalışmak doğası gereği bellek güvenliği sınırlarının dışına çıkmayı gerektirir. Donanım seviyesine indikçe kodun önemli bir kısmının unsafe bloklarıyla çevrelendiğini görürsünüz.

C. Mimari ve Derleyici Desteği

LLVM tabanlı olmayan özel DSP çekirdekleri, eski 8-bit/16-bit mikrodenetleyiciler veya üreticiye özel tescilli derleyici zincirlerinde (proprietary toolchains) Rust desteği bulmak ya imkansızdır ya da çok meşakkatlidir. C ve C++ ise neredeyse silisyumun olduğu her platformda çalışır.


3. C++ Tarafında Durum: Modern Standartlar (C++17 / C++20)

C++ savunucularının sıkça dile getirdiği gibi; Modern C++, 1998 yılının C++’ı değildir.

  • std::uniqueptr ve std::sharedptr ile dinamik bellek kontrolü büyük oranda güvenli hale gelmiştir.
  • std::string_view ve std::span gibi referans yapıları bellek kopyalamadan güvenli veri işlemeyi sağlar.
  • Derleme zamanı hesaplamaları (constexpr, consteval) donanım yapılandırma tablolarını sıfır çalışma zamanı maliyetiyle oluşturmaya imkan tanır.

Disiplinli bir ekip ve modern statik kod analiz araçları (Clang-Tidy, Cppcheck) ile yazılan C++ kodu, bellek güvenliği açısından endüstriyel kalitede sonuçlar vermektedir.


4. Karşılaştırma Özeti

KriterC++ (Modern C++17/20)Rust (Embedded Rust)
Ekosistem & SDK UyumuKusursuz (Tüm C SDK’leri doğrudan dahil edilir)C FFI / Binding katmanı gerektirir
Derleme HızıBüyük projelerde yavaşGenellikle daha da yavaş
Güvenlik GarantisiGeliştiricinin disiplinine ve araçlara bağlıDerleyici seviyesinde garanti
Öğrenme EğrisiKarmaşık ve genişBorrow checker nedeniyle dik
Donanım ÇeşitliliğiEvrensel (Tüm mimariler)LLVM destekli modern mimariler

5. Kişisel Sonuç

Benim bugünkü yaklaşımım şudur:

  • Eğer üzerinde çalıştığım kart standart dışı bir SDK’ya sahipse, karmaşık bir işletim sistemi çekirdeğiyle konuşuyorsa veya mevcut C kütüphanelerine yoğun bağımlılık varsa C++ hâlâ en rasyonel tercihtir.
  • Ancak yeni bir ARM Cortex-M veya RISC-V projesine sıfırdan başlanıyorsa, ağ üzerinden çalışan ve bellek güvenliği kritik olan bir IoT düğümü tasarlanıyorsa Rust kesinlikle şans verilmesi gereken çok güçlü bir alternatiftir.

İki dili birbirinin düşmanı gibi görmek yerine, her ikisinin de güçlü olduğu alanları doğru analiz edip projeye uygun aracı seçmek mühendisliğin temelidir.