Skip to content

34.2 从 C 调用 Rust 库

假设我们要在 Rust 中实现一个把字符串从小写变大写的函数,然后由 C 语言调用这个函数。实现代码如下:


rust
#[no_mangle]
pub extern "C" fn rust_capitalize(s: *mut c_char)
{
    unsafe {
        let mut p = s as *mut u8;
        while *p != 0 {
            let ch = char::from(*p);
            if ch.is_ascii() {
                let upper = ch.to_ascii_uppercase();
                *p = upper as u8;
            }
            p = p.offset(1);
        }
    }
}

我们在 Rust 中实现这个函数,考虑到 C 语言调用的时候传递的是char *类型,所以在 Rust 中我们对应的参数类型是*mut std::os::raw::c_char。这样两边就对应起来了。

这个函数是要被外部的 C 代码调用的,所以一定要用extern "C"修饰。用#[no_mangle]修饰主要是为了保证导出的函数名字和源码中的一致。这个并不是必须的,我们还可以使用#[export_name="my_whatever_name"]来指定导出名字。在某些时候,我们需要导出的函数名恰好在 Rust 中跟某个关键字发生了冲突,就可以用这种方式来规避。

使用如下编译命令,可以生成一个与 C 的 ABI 兼容的静态库。


rust
rustc --crate-type=staticlib capitalize.rs

下面我们再写一个调用这个函数的 C 程序:


rust
#include <stdlib.h>
#include <stdio.h>

// declare
extern void rust_capitalize(char *);

int main() {
    char str[] = "hello world";
    rust_capitalize(str);
    printf("%s\n", str);
    return 0;
}

使用如下命令编译链接:


rust
gcc -o main main.c -L. -l:libcapitalize.a -Wl,--gc-sections -lpthread -ldl

可以正确生成可执行程序。执行代码,可见该程序完成了预期中的功能。

Released under the MIT License