You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Rust中transmute将字节数组转元组时会重排字节?

为什么transmute转换后变量取值不符合预期?

示例代码

fn main() {
    let buffer: [u8; 16] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ];
    let (a, b, c, d, e): (u8, u8, u8, [u8; 4], [u8; 9]) = unsafe { core::mem::transmute(buffer) };
    println!("{a:#x}");
    println!("{b:#x}");
    println!("{c:#x}");
    println!("{d:#x?}");
    println!("{e:#x?}");
}

运行输出

0x4
0x5
0x6
[
    0x0,
    0x1,
    0x2,
    0x3,
]
[
    0x7,
    0x8,
    0x9,
    0xa,
    0xb,
    0xc,
    0xd,
    0xe,
    0xf,
]

问题

为何变量a、b、c未分别获取0x00、0x01、0x02的值,反而这些值被存入了变量d中?


原因及解决方案

这是因为Rust中默认的元组(以及未指定布局的结构体)采用repr(Rust)内存布局,编译器有权自由调整元素的内存排列顺序——哪怕元素的大小和对齐不会产生内存浪费,编译器也可能为了优化做调整。

你通过unsafe { core::mem::transmute }直接将数组的二进制内存转换为元组类型,本质上依赖了元组元素的内存顺序,但这个顺序是未定义的,没有语言层面的保证,所以才会出现和预期不符的取值结果。

方案1:使用安全的拆分方法

如果需要按固定顺序拆分数组,推荐用安全的方式,比如数组索引或者split_array_ref:

fn main() {
    let buffer: [u8; 16] = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f];
    let (head, rest) = buffer.split_array_ref::<3>();
    let (d, e) = rest.split_array_ref::<4>();
    let [a, b, c] = head;
    
    println!("{a:#x}");
    println!("{b:#x}");
    println!("{c:#x}");
    println!("{d:#x?}");
    println!("{e:#x?}");
}

方案2:使用固定布局的类型(若必须用transmute)

如果一定要用transmute,必须使用具有固定内存布局的类型,比如用#[repr(C)]修饰的结构体(repr(C)会严格按照声明顺序排列元素):

#[repr(C)]
struct SplitBuffer {
    a: u8,
    b: u8,
    c: u8,
    d: [u8; 4],
    e: [u8; 9],
}

fn main() {
    let buffer: [u8; 16] = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f];
    let split = unsafe { core::mem::transmute::<[u8; 16], SplitBuffer>(buffer) };
    
    println!("{split.a:#x}");
    println!("{split.b:#x}");
    println!("{split.c:#x}");
    println!("{split.d:#x?}");
    println!("{split.e:#x?}");
}

内容的提问来源于stack exchange,提问作者Matt Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:35:01