惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Spread Privacy
Spread Privacy
D
Docker
Stack Overflow Blog
Stack Overflow Blog
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
F
Full Disclosure
美团技术团队
Y
Y Combinator Blog
N
Netflix TechBlog - Medium
Security Latest
Security Latest
C
Check Point Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
罗磊的独立博客
A
Arctic Wolf
S
Schneier on Security
T
Threatpost
C
CERT Recently Published Vulnerability Notes
L
LangChain Blog
博客园 - 叶小钗
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 聂微东
T
The Exploit Database - CXSecurity.com
W
WeLiveSecurity
Engineering at Meta
Engineering at Meta
C
Cybersecurity and Infrastructure Security Agency CISA
GbyAI
GbyAI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
H
Heimdal Security Blog
L
LINUX DO - 热门话题
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
O
OpenAI News
G
GRAHAM CLULEY
M
MIT News - Artificial intelligence
S
Security @ Cisco Blogs
博客园 - 司徒正美
N
News and Events Feed by Topic
Microsoft Azure Blog
Microsoft Azure Blog
Cisco Talos Blog
Cisco Talos Blog
P
Palo Alto Networks Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Schneier on Security
Schneier on Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
月光博客
月光博客
The Last Watchdog
The Last Watchdog
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
C
Cisco Blogs
雷峰网
雷峰网

博客园 - PKICA

rust性能优化与安全边界 rust并发与异步编程 如何预防rust不良的代码设计总结 rust类型系统与零成本抽象 rust内存模型 告别大显存依赖!用 Rust 新一代深度学习框架 Burn 打造纯 CPU 文本分类推理引擎 rust类型系统标记 编译配置解答 git实用命令 rust底层设计理念值得注意的几个地方总结 rust可变引用作为函数参数的机理详解 Rust内存重解释transmute C与Rust类型映射 Rust FFI 安全抽象范式 rust延迟初始化原语 rust重借用机制与原理 rust参数传递模型 汇编语言语法详解 gdb汇编调试 gdb-pwndbg的安装与使用指南 gdb调试插件gef C语言thread_local linux系统readelf命令使用指南 gcore转储进程内存 gdb查看命令 RGB与YUV颜色编码的区别 Rust原子类型 C++ STL求两个集合交集差集 gdb调试集锦 ubuntu24.0.4使用root用户登录 ubuntu24.0.4输入密码后跳回登录界面 AI内存压缩技术TurboQuant及存疑 ubuntu切换到指定内核版本 在没有顶级科技大佬直接背书的情况下deepseek为啥能够异军突起? HuggingFace和deepseek的关系 当前主流AI大模型 Rust写时克隆Cow系列2
联合体union在rust和C语言中有什么区别
PKICA · 2026-07-22 · via 博客园 - PKICA

Rust 中的 union(联合体)在内存布局和底层逻辑上与 C 语言的 union 完全一致,其存在的首要目的就是为了与 C 语言进行无缝的 FFI(外部函数接口) 交互。

但在类型安全、生命周期管理以及编译器约束方面,两者存在着本质的区别:

1. 读写操作的安全级别不同 (Safety)

  • C 语言:读写 union 的任何字段都是完全自由且隐式安全的。编译器允许你随时读取任意字段(即使你刚刚写入的是另一个字段),这在 C 中极易引发未定义行为(UB)。
  • Rust 语言:
    • 写入字段是安全的(Safe)。
    • 读取字段是绝对不安全(Unsafe)的。你必须将读取操作包裹在 unsafe 块中。因为 Rust 编译器在编译期无法追踪当前 union 内存中到底存放的是哪一个字段的有效数据。
#[repr(C)] // 保持与 C 一致的内存布局
union MyUnion {
    f1: u32,
    f2: f32,
}

let mut u = MyUnion { f1: 1 };
u.f2 = 2.0; // 写入是安全的

// 读取必须使用 unsafe
unsafe {
    println!("{}", u.f2); 
}

2. 字段类型的限制不同 (Type Restrictions)

  • C 语言:只要是非结构化或大小可确定的类型(除了带变长数组的结构体等特例),几乎所有类型都可以放入 union
  • Rust 语言:由于 Rust 拥有严格的所有权和析构(Drop)机制,Rust 对 union 字段的类型有极强的限制:
    • 禁止包含自动析构类型:union 的字段不能包含实现了 Drop 特征的类型(例如 StringVec<T>Box<T> )。
    • 原因:当 union 离开作用域被销毁时,编译器不知道应该调用哪个字段的 Drop 函数。如果盲目调用,会导致内存双重释放(Double Free)或释放了错误的指针。
    • 绕过限制:如果非要包含非 Copy 类型,必须使用 std::mem::ManuallyDrop 包裹字段,显式告诉编译器放弃自动析构,由开发者手动管理生命周期。

3. 模式匹配支持 (Pattern Matching)

  • C 语言:不支持原生模式匹配,只能通过 switch-case 配合一个外部的 tag(标签)变量手动判断。
  • Rust 语言:支持在 unsafe 块中对 union 进行模式匹配(Pattern Matching),但由于编译器无法保证活跃字段,匹配必须显式指定你想要读取的那个具体字段名称。
// 必须在 unsafe 块中对指定字段进行匹配
unsafe {
    match u {
        MyUnion { f1: 10 } => println!("f1 is 10"),
        MyUnion { f1 } => println!("f1 is {}", f1),
    }
}

4. 派生宏的支持 (Derive Traits)

  • C 语言:没有通用的打印、比较、复制的机制,全部需要手动编写函数。
  • Rust 语言:Rust 的 union 可以使用部分标准派生宏(如 #[derive(Clone, Copy)]),但不能派生 PartialEqEqHashDebug。因为这些特性的实现依赖于清晰地读取字段值,而编译器在安全上下文中无法得知哪一个字段有效。

💡 官方推荐的 Idiomatic 替代方案:enum

在 Rust 中,如果你不需要和 C 语言的代码做内存对接,绝对不应该使用 union

Rust 官方推荐的惯用替代方案是 enum(标签联合/代数数据类型)。Rust 的 enum 在底层是一个“安全的联合体”,它不仅包裹了数据,还在内存中额外占用 1 个字节作为“标签(Tag)”,从而让编译器在编译期和运行时都能完美追踪当前活跃的究竟是哪一个分支:

// Rust 官方推荐的“安全联合体”写法
enum MySafeUnion {
    F1(u32),
    F2(String), // 完美支持 Drop 类型
} // 它是安全的,支持模式匹配,读取不需要 unsafe

参考资料:

1.C++联合