p[j] = p[j-1];
into *p.offset(j as isize) = *p.offset((j - 1 as libc::c_int) as isize);
which is unmaintainable.If you put in
void insertion_sort(int const n, int const p[])
you get pub unsafe extern "C" fn
insertion_sort(n: libc::c_int,
mut p: *const libc::c_int)
C has no way to say how big p is. (Biggest flaw in the design of C).
That info is essential to translating this properly. The translator needs either a hint from the user, or inference from examining the calls to the function.Now, if you could stick something like
ASSERT(LENGTHOF(p) == n);
which would be ignored by C if ASSERT was defined to ignore it,
and the Rust translator understood that, it could use a Rust array, which has a size.
Now the output Rust code could use subscripts properly.Generating constraints like that is a hard problem, but providing an interactive tool which prompts the user on where to insert them is not.
C2Rust includes a refactoring tool that (in some, currently very limited circumstances) let us lift raw C pointers to Rust references (to slices) as a step towards using safe Rust constructs. This is obviously not something that can be 100% automated but our goal is to see how far we can reasonably go. Lots of work ahead but we 100% agree that some level of automation is highly desirable here.
Isn't that the idea?
Sure, it makes it into essentially a blob of uneditable code. But it allows you to integrate it with rust code and build the whole thing together.
This is a classic problem with computer language conversion - you lose the idioms of both the input language and the output language in translation.
No, it doesn't. It retains comments, the names of variables, and most of the structure of the code. You're meant to be able to factor the unsafe behaviours out incrementally from there (and there are a lot of bundled and associated tools meant for exactly that). I ran an example through c2rust the other day and rustc told me immediately that I had functions that didn't need to be marked unsafe. switch statements are probably the thing that suffers most with c2rust, though I think there's a tool for that.
void send(volatile short *to, short *from, int count)
{
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
While the result from c2rust is even less maintainable than original interleaved-loop-switch, I'm impressed that it looks like they have a robust way to handle bizarre control flow. (The output from c2rust is not reproduced here to save space, you can try it on https://c2rust.com/ )For C, almost everything is written by you, especially when it comes to macros. There are some “basics” that you pick up here and there, which you can copy-paste more or less.
The C preprocessor is a beautiful thing, but can get a bit tedious. Sometimes a lot tedious. But shit is textual replacement powerful!
The first versions were written in Prolog.