bigywater.tech
Rust · 117

Option<&T> 的空指针优化

Option<&T> 为什么没有额外开销?在 FFI 里它又怎么变成 C 的可空指针?这篇不靠文档,而是直接读 None 的位模式,并真的调用 libc 的 getenv、strchr、free 来验证。

0x0
Option<&T> 等 None 的位模式
2 个 libc 函数
用 Option<&T> 作返回值直接接收 NULL 的 getenv 与 strchr
16 对 24 字节
Option 链表节点与「裸指针 + bool」节点的大小

None 就是空指针

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      None 的位模式:&u32 0x0  &mut u32 0x0  Box<u32> 0x0  NonNull<u32> 0x0  fn() 0x0  extern "C" fn() 0x0
      大小:8 8 8 8 8 8(都是一个指针)
      对照:*const u32 8 字节,Option<*const u32> 16 字节(裸指针可以为空,没有 niche)

通用的 niche 规则见Enum 的内存布局。

接收 C 的可空指针

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      getenv("HOME") → Some(C 返回了非空指针)
      getenv("U117_NOT_SET") → None(C 返回了 NULL)
      strchr("hello world", 'w') → Some("world")  strchr(.., 'z') → None

FFI 调用的基础见FFI 调用 C 函数。

把 Option 传给 C

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      free(None) 没有崩溃(传给 C 的是 NULL)
      malloc(16) → Some(非空指针)

没有 niche 的代价

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      Option<Box<Node>> 的链表节点:16 字节;Option<NonNull<Node>>:16 字节;裸指针 + bool 标志:24 字节
      Option<u64> 做可选索引:24 字节;Option<NonZeroU64>:16 字节

分步演示

Option<&T> 的空指针优化
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。FFI 直接链接系统 libc,没有使用 bindgen
    • 没有验证:Option<&T> 与 C 的 const T* 在 ABI 层面是否在所有平台等价(只在本机 aarch64 验证)、返回非空但悬空指针时的后果、Option 作为回调参数的实际调用、其它 niche 类型(如 Option)在 FFI 上的可用性
    京ICP备2026067502号-1京公网安备11010502063487号