Rust 1.99 允许自定义 C 变参函数:省略号后面终于能是 Rust 代码

Rust 1.99 允许自定义 C 变参函数:省略号后面终于能是 Rust 代码

6小时前
duguying
2 阅读
来源:GitHub

Rust 1.99.0 稳定了 C 变参函数定义与 #[unsafe(naked)] 变参形式,FFI 胶水不再需要 C 文件;半个月后的 1.99.1 又修了 x86_64 FFI bool 误编译。

相关标签

#GitHub#Trending#Rust#FFI#编译器

一个从 1.0 时代悬到现在的缺口

Rust 1.99.0(10 月 1 日)的发布说明里有一行很短的条目:稳定 C 变参函数定义(PR #155697)。配套的还有一条:允许用 #[unsafe(naked)] 函数定义 C 变参函数(PR #159746)。

对不写 FFI 的人来说,这两行什么都不是;对写过绑定层的人来说,它意味着一个从 Rust 1.0 就存在的边界终于被推开了。过去的稳定版 Rust 能调用 C 的变参函数——extern "C" { fn printf(fmt: *const c_char, ...); } 一直合法——但不能定义一个。也就是说,”接受可变数量参数、再把它们转发给 C”这类活,只能在 nightly 上开 c_variadic,或者老老实实写一个 C 胶水文件、再把它编进构建脚本。

被卡住的正是这些场景:实现一个 printf 风格的日志接口;包一层 ioctl;给需要变参回调的 C 库(trace、断言、错误处理钩子)提供 Rust 侧实现;把只提供变参入口的 C++ / Objective-C 接口桥接进 Rust。现在可以直接在 .rs 文件里写 extern "C" fn my_log(fmt: *const c_char, mut args: ...),用 core::ffi::VaList 逐项取出参数。ABI 细节仍然和平台绑定,VaList 也仍然要 unsafe,但”必须写 C”这个前置条件没了。

同一版里几处与底层相关的改动

  • #[my_macro] mod foo; 稳定(PR #157857):外部模块(mod foo;)现在可以出现在属性宏或 derive 宏展开出的任意位置,此前只能写成内联模块。对做代码生成的框架来说,这条比看起来重要——大项目终于能一边用属性宏展开,一边保持模块按文件拆分。
  • asm! 在 x86 上支持通过向量寄存器传 128 位整数(PR #159525)。
  • 明确保证 UnsafeCell 的内容可以不经过 get 直接访问,invalid_reference_casting lint 相应调整(PR #159730、#159960)。这是把一条实践中早已依赖的行为写进文档。
  • 新增 allow-by-default 的 raw_borrows_via_references lint,专门找”引用刚产生就衰减成裸借用”的写法;unconditional_panic 扩展到 chunks / windows 传 0 长度时必然 panic 的调用。

半个月后的补丁说明风险还在

1.99.1(10 月 16 日)只修了三件事,第一条是 x86_64 上 FFI bool 返回值被误编译(issue #163911)。另外两条是 UEFI 与嵌入式目标缺 wcslen 符号、macOS 上给 rust-lld 补 libLLVM 的 rpath。

把这条和上面的变参稳定化放在一起看,恰好构成一个提醒:FFI 边界是编译器最容易出错、也最少被测试覆盖的地方。bool 的 ABI 表示只有 1 字节,而 C 侧习惯用 int 传,这类”看起来显然”的约定一旦在代码生成阶段被优化掉,症状就是返回值随机翻转,且只在 release 构建里出现。新能力开放后,会有更多项目把变参逻辑搬进 Rust,这类边界问题的暴露面只会更大。

项目目前 121,465 star,当日新增 192。这个量级的项目已经不太靠功能吸引人,它的变化更多体现在”哪些以前必须绕路的事,现在可以直着走了”。

仓库地址:https://github.com/rust-lang/rust

返回列表

更多资讯

想看更多优质内容?

浏览所有资讯