外部函数接口FFI

2023-12-17 03:12
文章标签 接口 函数 外部 ffi

本文主要是介绍外部函数接口FFI,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在某些场景下,你的RUST代码可能需要与另外一种语言编写的代码进行交互。RUST为此提供了extern关键字来简化创建和使用外部函数接口(Foreign Function Interface,FFI)。FFI是编程语言定义函数的一种方式,它允许其它编程语言来调用这些函数。

extern "C" {fn abs(input: i32) -> i32;
}fn main() {unsafe {println!("Hello, world!{}", abs(-3));}
}

这段代码在extern "C"列出了我们想要调用的外部函数名称及签名,其中的"C"指明了外部函数使用的二进制接口(Application Binary Interface,ABI):它被用来定义函数在汇编层面的调用方式。我们使用的"C" ABI正是C编程语言的ABI,也是最常见的ABI格式之一。

ABI前世今生

我们浏览了Rust-ABI 的前世今生这篇博客。

在计算机软件中,应用二进制接口(ABI)是两个二进制程序模块之间的接口;通常这些模块之一是库或操作系统工具,而另一个是用户正在运行的程序。

C-ABI包含两个关键的内核:

  • 数据的内存布局方式
  • 函数如何调用

RUST目前的ABI并不稳定,即RUST不保证内存中数据结构的调用约定和内存布局不被改变。

这里有几个示例来说明什么是不稳定的ABI

// 虽然下面的结构体本质是相同的,但是 Rust 编译器不保证给予它们字段相同的内存偏移量
struct A(u32, u64);
struct B(u32, u64);// Rust 编译器不保证字段的顺序和定义的一样
struct Rect {x: f32,y: f32,w: f32,h: f32,
}

RUST编译器会对上面的结构体进行优化,如果内存布局是确定的,就不利于优化了。比如没有办法对结构体字段进行重排以便达到最小化内存占用的优化目标。内存布局不确定性也有利于模糊测试(Fuzzer),因为模糊测试需要将字段随机排列以便更容易地暴露潜在的问题。

#[repr(C)]
struct MyStruct {x: u32,y: Vec<u8>,z: u32,
}

对于该示例来说,虽然使用了#[repr(C)]让结构体字段的顺序确定了,但是字段的偏移量依然无法确定,因为Vec<8>没有任何确定性的排序,从而z的偏移量是无法确定的。所以这种类型不适合使用CFFI

作者尝试动态加载实现插件,发现RUST ABI不稳定带来的问题比想象的更加严重。在这之前,他一直认为即使RUST ABI不稳定,只要库和主二进制文件是用相同的编译器以及std等版本编译的,就可以安全地动态加载一个库。然而事实证明,ABI不仅仅是可能在不同编译版本之间发生”断裂“,在编译器执行的过程中也会发生断裂,即RUST编译器并不保证同一个类型的布局在每次执行的时候都一致,类型布局可以随着每次编译而改变。所以他的方案是使用#[repr(C)]C-ABI以及使用abi_stable来获得稳定的std库。

作者后面尝试使用abi_stable来开发插件系统。abi_stable是按模块来构建的,并且提供了很多FFI安全的类型(指FFI边界提供了稳定的内存布局),包括trait对象的支持及提供了处理FFI边界panic的方法。

这篇关于外部函数接口FFI的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/502886

相关文章

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

go中空接口的具体使用

《go中空接口的具体使用》空接口是一种特殊的接口类型,它不包含任何方法,本文主要介绍了go中空接口的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录接口-空接口1. 什么是空接口?2. 如何使用空接口?第一,第二,第三,3. 空接口几个要注意的坑坑1:坑2:坑3:接口-空接口1. 什么是空接

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

kotlin的函数forEach示例详解

《kotlin的函数forEach示例详解》在Kotlin中,forEach是一个高阶函数,用于遍历集合中的每个元素并对其执行指定的操作,它的核心特点是简洁、函数式,适用于需要遍历集合且无需返回值的场... 目录一、基本用法1️⃣ 遍历集合2️⃣ 遍历数组3️⃣ 遍历 Map二、与 for 循环的区别三、高

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景