1 unstable release

Uses new Rust 2024

new 0.1.0 Mar 26, 2025

#157 in Programming languages

GPL-2.0-or-later

300KB
6.5K SLoC

CCARP - (trans)Compile C And Rust Partially

CCARP is a command line utility made with the sole purpose of transcompiling or transpiling C programs into Rust.

Does it actually work?

Somewhat.

At the moment CCARP can be used to rustify simple C programs, but for more complex programs it will most likely run into an error. If it succeeds however, it will produce a Rust program which either compiles or almost compiles, in either way its meaning will be similar to the C code (if one manages to solve all conflicts within the generated code).

An example

Example C code:

int fib(int n) {
    int a=0,b=1,c;
    for (int i=0;i<n;i++) {
        c=a+b;
        a=b;
        b=c;
    }
    return a;
}
int main() {
    return fib(11);
}

Generated Rust code (after formatting and simplification):

pub fn fib(mut n: i32) -> i32 {
    let mut a: i32 = (0);
    let mut b: i32 = (1);
    let mut c: i32;
    let mut i: i32 = (0);
    while (i < n) {
        {
            (c = (a + b));
            (a = b);
            (b = c);
            (i += 1);
        }
    }
    return (a);
}
pub fn main() -> std::process::ExitCode {
    return std::process::ExitCode::from((fib(11) as u8));
}

How to use it?

CCARP can be both a library and an executable.

You can use it as a dependency

cargo add ccarp

in this case translate, translate_single_file and translate_project functions are available.

Or alternatively you can install it as an executable via

cargo install ccarp

After that a

ccarp --help

command will show you how it can be used.

What does CCARP implement from C?

CCARP mainly implements the core of C, as in the syntax approximate meaning of C without most macros and standard library. (Also without goto, labels and variadic functions amongst other things.)

What will most likely work:

  • standard primitive types (char, short, int, long, long long, etc.)
  • expressions with primitive types (e.g. 1 + 2, a + b, 1 ? a << 2 : b & c * 2)
  • fixed size arrays (int arr[5],{1,2,3})
  • simple declarations (int c=0;,typedef int int32;)
  • most statements
    • if (1==2) { a=1; } else { a=2; }
    • for (int i=0;i<10;i++) { a+=2; }
    • while (a<5) { a++; }
  • switch with some restrictions
switch (num[i]) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    {
        res *= 10;
        res += num[i] - '0';
    }
    break;

    default:
        return 0;
    break;
}

in general:

switch ($EXPR) {
    case $LITERAL:
    case $LITERAL_2:
    ...
    case $LITERAL_N:
    $BODY
    break;

    ...

    default:
    $BODY
    break;
}
  • function definitions (int add_two(int n) { return n+2; })

How does CCARP deal with types?

Primitive types

Primitive types are translated to the following Rust types:

c type rust type
char u8
unsigned char u8
signed char i8
short i16
unsigned short u16
int i32
unsigned int u32
long i64
unsigned long u64
long long i64
unsigned long long u64
float f32
double f64
long double f64
bool ~i8
void ()

Arrays and Pointers

Arrays and pointers are somewhat dependent on compiler flags in translation. Basic array and pointer types:

c type rust type
int * *mut i32
const int * *const i32
int *const &mut i32
const int *const &i32
int arr[N] [i32;N]

Conversions

CCARP applies a best-effort conversion between types, but not all types can be trivially converted into another. This is why for example void * does not compile to valid Rust at the moment.

How does CCARP work?

CCARP uses Pest for parsing its inputs into tokens; after tokenisation it parses tokens into C translation units and creates a C AST (Abstract Syntax Tree for short) from it; the next step after that is logically morphing the C AST into a Rust AST and from that the program can produce a Rust code (which might or might not work).

In fewer words:

  1. C Code
  2. Tokenisation
  3. Parsing tokens into structures
  4. C AST
  5. Rust AST
  6. Rust Code

Dependencies

~2.1–2.9MB
~58K SLoC