extern#[no_mangle]ExternBlock 及其属性 link 和 link_namestd:os:raw 模块std:ffi 模块extern
extern可以实现 Rust 语言与其它语言的交互,这是 Rust 外部函数接口 FFI 的基础。extern 函数fn前使用关键字extern,可以创建一个允许其他语言调用 Rust 函数的接口。extern "Rust",默认的 ABI,在 Rust 代码中对任何普通函数fn foo()声明时都将使用该 ABI。extern "C",指定使用 C-ABI,类似extern fn foo(),无论 C 编译器支持哪种默认设置。extern "system",通常类似extern "C",但在 Win32 平台上,它是"stdcall",或用于链接到 Windows API。// ffi/c-call-rust/src/lib.rs
pub extern "C" fn call_from_rust() {
println!("This is a Rust function for C!");
}
#[no_mangle]
no_mangle,用来关闭 Rust 的名称修改(name mangling)功能。Mangling 是编译器在解析名称时,修改我们定义的函数名称,增加一些用于其编译过程的额外信息。Undefined symbols for architecture x86_64:
"_call_from_rust", referenced from:
_main in main-77cb59.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1
#[no_mangle] ,告诉 Rust 编译器不要修改此函数的名称。// ffi/c-call-rust/src/lib.rs
#[no_mangle]
pub extern "C" fn call_from_rust() {
println!("This is a Rust function for C!");
}
ExternBlock
extern可以声明一个外部块(ExternBlock),通过外部块的形式,可以在 Rust 代码中调用外部代码。extern声明一个外部块的语法格式如下:extern Abi? {
InnerAttribute*
ExternalItem*
}
Abi表示调用库使用的 ABI 标准,可选值为1.1节中提到的 ABI 字符串。缺省情况下,外部块默认为标准的 C-ABI。在定义外部块的时候,可以使用 link和 link_name 这两个属性,通过它们来控制外部块的行为。link
link用来指定原生库的名称,编译器根据它为外部块链接原生库。它支持的键有:name,kind和wasm_import_module,name用来定义要链接的原生库的名称。 kind是一个可选值,通过它来指定原生库的类型,它有以下三种可选的值:dylib,表示为动态库。如果未指定kind,则它为默认值。static,表示为静态库。framework,表示 macOS 的框架,这仅对 macOS 目标有效。link设定了原生库的类型kind,则必须包括原生库的名称name。wasm_import_module可用于指定 WebAssembly 模块的名称,如果未指定wasm_import_module,则模块名称默认为env。#[link(name = "c_library")]
extern "C" {
fn c_function(input: i32) -> i32;
}
link_name
link_name,指定原生库中函数或静态对象的名称,编译器根据它可以为外部块链接原生库并导入该名称定义的函数或静态对象。extern "C" {
#[link_name = "c_function_name"]
fn name_in_rust();
}
// ffi/rust-call-c/src/main.rs
// 标准库<stdlib.h>内置的abs函数
extern "C" {
#[link_name = "abs"]
fn abs_in_rust(input: i32) -> i32;
}
fn main() {
unsafe {
println!("abs(-1) is {}", abs_in_rust(-1));
}
}
std::os::raw 和std::ffi 这两个模块提供了这方面的支持。std::os::raw 模块std::os::raw 模块[2]提供了一些类型与 C 语言定义的类型相匹配,以便与 C 语言交互的代码引用正确的类型。c_char |
char类型 |
c_double |
double类型 |
std::ffi 模块std::ffi 模块[3]提供了一组实用的程序,主要用于外部函数接口 FFI 的绑定,以及用在与其他语言传递类 C 字符串的代码中。CString和CStr很有用。CStrCStr来表示,它和str类型对应,表明并不拥有这个字符串的所有权。所以CStr表示一个以终止符\n结尾的字节数组的引用,如果它是有效的 UTF-8 字符串,则可以将其转换为 Rust 语言中的&str。实现从 C 语言到 Rust 语言的字符串传递。CStringCString来表示用以传给 C 程序的字符串。CString以终止符\n结尾,并且没有内部\n字符,代码可以首先从 Rust 语言的普通字符串创建CString类型,然后将其作为参数传递给使用 C-ABI 约定的字符串函数。实现从 Rust 语言到 C 语言的字符串传递。use std::ffi::CString;
use std::os::raw::c_char;
#[no_mangle]
pub extern rust_printer(input: *const c_char) {
let mut hello = String::from("Hello World!");
let c_str_to_print = CString::new(hello).unwrap();
}
OsString和OsStr很有用。OsString表示传递给操作系统的拥有所有权的字符串。例如,env::var_os()用于查询环境变量,它返回一个Option<OsString>。如果环境变量存在,将获得Some(os_string),然后可以将其转换为 Rust 字符串。OsStr表示传递给操作系统的字符串引用,可以按照与OsString类似的方式将其转换为 UTF-8 编码的 Rust 字符串切片。std::ffi::c_void等同于 C 语言中的void类型。std::os::raw 模块,https://doc.rust-lang.org/stable/std/os/raw/index.htmlstd::ffi 模块,https://doc.rust-lang.org/std/ffi/index.html原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。