
A Case for Migrating from C/C++
R4W Development Team
(Aida, Joe Mooney, Claude
Code)
December 2025
Making the Case to C/C++ Developers
“We’ve been doing SDR in C/C++ for decades. Why change?”
This presentation addresses: 1. The problems we’re actually solving 2. What Rust brings that C/C++ doesn’t 3. Performance comparisons (real numbers) 4. Migration strategies 5. The things Rust is NOT good at
| Bug Class | Example | Consequence |
|---|---|---|
| Buffer overflow | Wrong FFT size | Crash, data corruption |
| Use-after-free | Callback with freed context | Random behavior |
| Data race | TX/RX thread conflict | Intermittent failures |
| Null pointer | Missing device check | Segfault |
Real impact: Hours/days of debugging, sanitizer runs, code review.
// This doesn't compile:
let data = vec![1, 2, 3];
let reference = &data[0];
data.push(4); // ERROR: cannot borrow `data` as mutable
// because it is also borrowed as immutable
println!("{}", reference);The compiler catches: - Buffer overflows - Use-after-free - Data races - Null pointer dereference
pub fn apply_fir_filter(samples: &mut [IQSample], coeffs: &[f64]) {
for i in coeffs.len()..samples.len() {
samples[i] = coeffs.iter()
.enumerate()
.map(|(j, &c)| samples[i - j] * c)
.sum();
}
} // Bounds checked at compile time“Memory safety checks must cost performance.”
Rust’s safety is compile-time, not runtime.
| Operation | R4W (Rust) | GNU Radio (C++) | Speedup |
|---|---|---|---|
| FFT 1024-pt | 371 MS/s | 50 MS/s | 7.4x |
| FFT 4096-pt | 330 MS/s | 12 MS/s | 27x |
| FFT 2048-pt | 179 MS/s | ~25 MS/s | 7x |
Why faster? - rustfft optimized for Rust memory model - Zero-copy lock-free buffers - No Python/SWIG overhead
| Metric | Target | R4W Actual |
|---|---|---|
| FFT p99 latency | < 100 µs | 18 µs |
| BPSK roundtrip p99 | < 100 µs | 20 µs |
| FHSS hop timing p99 | < 500 µs | 80-118 µs |
| Page faults (RT mode) | 0 | 0 |
| Hot-path allocations | 0 | 0 |
Same RT primitives as C: mlockall,
SCHED_FIFO, CPU affinity.
// Calling C from Rust
extern "C" {
fn fftw_plan_dft_1d(n: c_int, in_: *mut c_double,
out: *mut c_double, sign: c_int,
flags: c_uint) -> *mut fftw_plan;
}Keep existing C/C++ application, call R4W for specific functions.
#include <r4w.hpp>
auto lora = r4w::Waveform::lora(7, 125000.0);
auto samples = lora.modulate(bits);Start with stateless DSP functions: - Filters - FFT wrappers - Modulation algorithms
Legacy maintenance in C++, new features in Rust.
| Aspect | Value |
|---|---|
| Memory safety | Bugs caught at compile time |
| Performance | Equal or better than C++ |
| Tooling | cargo, rust-analyzer, clippy |
| Testing | 527 tests across 8 crates |
| Docs | Auto-generated from code |
| FPGA | Zynq + Lattice acceleration |
| Isolation | 8 levels of waveform sandboxing |
| Language | Lines | Files | Purpose |
|---|---|---|---|
| Rust | 66,572 | 217 | Core implementation (79%) |
| Coq | 6,324 | 27 | Formal verification |
| C/C++ | 2,037 | 5 | FFI bindings |
| Total | 84,467 | 359 |
crates/r4w-ffi/examples/| If you value… | Rust provides… |
|---|---|
| Correctness | Compile-time safety |
| Performance | Zero-cost abstractions |
| Maintainability | Strong typing, modern tooling |
| Velocity | Fast builds, integrated testing |
The question isn’t “Why Rust?”
It’s “Why are we still debugging buffer overflows?”