
Rust 1.99 允许自定义 C 变参函数:省略号后面终于能是 Rust 代码
Rust 1.99.0 稳定了 C 变参函数定义与 #[unsafe(naked)] 变参形式,FFI 胶水不再需要 C 文件;半个月后的 1.99.1 又修了 x86_64 FFI bool 误编译。
相关标签
一个从 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_castinglint 相应调整(PR #159730、#159960)。这是把一条实践中早已依赖的行为写进文档。 - 新增 allow-by-default 的
raw_borrows_via_referenceslint,专门找”引用刚产生就衰减成裸借用”的写法;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。这个量级的项目已经不太靠功能吸引人,它的变化更多体现在”哪些以前必须绕路的事,现在可以直着走了”。
更多资讯
想看更多优质内容?
浏览所有资讯