C
C
—
—
—
C-to-Rust
-
- ****malloc/free
- ****goto
-
- RustCRust
CRust
2.1 — malloc/free → Box/Vec + Drop
C
Person* person_new(const char* name, int age) {
Person* p = (Person*)malloc(sizeof(Person));
if (p == NULL) return NULL;
p->name = (char*)malloc(strlen(name) + 1);
if (p->name == NULL) { free(p); return NULL; }
strcpy(p->name, name);
p->age = age;
return p;
}
void person_free(Person* p) {
if (p != NULL) { free(p->name); free(p); }
}Rust
struct Person { name: String, age: u32 }
impl Person {
fn new(name: &str, age: u32) -> Self {
Person { name: name.to_string(), age }
}
}
// Drop trait | C | Rust | |
|---|---|---|
| mallocNULL | StringNULL | |
| person_free | Drop | |
2.2 +void* → Trait /
C
typedef void (*callback_t)(void* ctx, int value);
void process_numbers(int* arr, int len, callback_t cb, void* ctx) {
for (int i = 0; i < len; i++) cb(ctx, arr[i]);
}Rust
fn process_numbers(arr: &[i32], mut cb: impl FnMut(i32)) {
for &val in arr { cb(val); }
}| C | Rust | |
|---|---|---|
| void* | ||
| ctxNULL | ||
2.3 → Trait
C
typedef struct { void (*speak)(Animal* self); void (*destroy)(Animal* self); } AnimalVtable;
typedef struct { const AnimalVtable* vtable; } Animal;Rust
trait Animal { fn speak(&self); }
struct Dog { name: String }
impl Animal for Dog { fn speak(&self) { println!("{}: Woof!", self.name); } }2.4 define → const
| define | const/static | |
|---|---|---|
2.5 define → /
C
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int y = MIN(x++, 10); // x++
int z = MIN(3 & 5, 4); // Ruststd::cmp::min``std::mem::swap
2.6 goto cleanup → RAII + Drop + ?
C
int process(const char* path) {
Resource res = {0};
res.file = fopen(path, "r"); if (!res.file) goto cleanup;
res.buffer = malloc(4096); if (!res.buffer) goto cleanup;
// ...
cleanup:
if (res.data) free(res.data);
if (res.buffer) free(res.buffer);
if (res.file) fclose(res.file);
return ret;
}Rust
fn process(path: &str) -> Result<(), io::Error> {
let mut file = File::open(path)?;
let mut buffer = vec![0u8; 4096];
let n = file.read(&mut buffer)?;
Ok(()) // bufferfile
}2.7 + → Result/Option
C
int parse_int(const char* s, int* out) {
if (!s || !out) return -1;
char* endptr;
long val = strtol(s, &endptr, 10);
if (endptr == s || *endptr != '\0') return -1;
*out = (int)val;
return 0;
}Rust
fn parse_int(s: &str) -> Result<i32, ParseIntError> { s.parse::<i32>() }2.8 NULL → Option
Cif (head == NULL)RustOption<T>""match
| c2rust | CRustunsafe Rust |
| bindgen | CRust FFI |
| cbindgen | RustC ABI |
| valgrind | C |
| AddressSanitizer |
cargo install c2rust
c2rust transpile input.c --emit=builders -o output.rsc2rustunsafeRust
C
typedef struct { int* items; int count, capacity; } IntList;
IntList* list_new(void) {
IntList* list = malloc(sizeof(IntList)); // ① malloc
list->items = malloc(8 * sizeof(int)); // ② malloc
list->count = 0;
list->capacity = 8;
return list;
}
void list_add(IntList* list, int value) {
if (list->count >= list->capacity) {
list->capacity *= 2; // ③
list->items = realloc(list->items, // ④ realloc
list->capacity * sizeof(int));
}
list->items[list->count++] = value; // ⑤
}
int list_get(IntList* list, int index) {
return list->items[index]; // ⑥
}Rust3fn filter_positive(arr: &[i32]) -> Vec<i32> { arr.iter().copied().filter(|&x| x > 0).collect() }
| 1. | grep | |
| 2. | malloc/free | |
| 3. | goto | |
| 4. | ||
| 5. Rust | CRust |