C

C

 — 
 — 
 — 

C-to-Rust


  1. ****malloc/free
  2. ****goto

  3. 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 
CRust
mallocNULLStringNULL
person_freeDrop

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); }
}
CRust
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

defineconst/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

c2rustCRustunsafe Rust
bindgenCRust FFI
cbindgenRustC ABI
valgrindC
AddressSanitizer
cargo install c2rust
c2rust transpile input.c --emit=builders -o output.rs

c2rustunsafeRust

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. RustCRust