传递可变原始指针到C FFI后值异常问题排查
Rust FFI中C结构体u32数组值不匹配问题排查
我在为接收结构体指针并修改的C函数编写Rust FFI接口时遇到问题:C代码中打印的state数组字节值符合预期,但回到Rust后打印的state数组u32值完全不符。相关代码如下:
C代码
#include <stdint.h> #include <stdio.h> struct my_struct { uint64_t len; uint32_t state[4]; int count; }; int modify_struct(struct my_struct *x) { // 此处修改结构体内容 // 打印预期的字节序列 uint8_t *bytes = (uint8_t *)x->state; for (int i = 0; i < 16; i++) printf("%02x", bytes[i]); printf("\n"); return 0; }
Rust代码
use libc::c_int; #[repr(C)] #[derive(Debug, Default)] struct MyStruct { length: u64, state: [u32; 4], count: c_int } extern "C" { fn modify_struct(x: *mut MyStruct) -> c_int; } fn main() { let mut x = MyStruct::default(); unsafe { modify_struct(&mut x); } // 打印u32值,结果与C端不符 for i in 0..4 { println!("{:08x}", x.state[i]); } }
问题排查与解决方案
1. 对齐打印方式,确认内存内容是否一致
C端打印的是state数组的原始字节序列,而Rust端直接打印u32类型值,两者差异可能只是字节序(大小端)导致的表示不同,而非内存内容错误。
在Rust中按字节打印state数组,和C端输出对比:
// 替换main函数中原打印代码 let bytes = unsafe { std::slice::from_raw_parts(x.state.as_ptr() as *const u8, 16) }; for &b in bytes { print!("{:02x}", b); } println!();
- 如果这段输出和C端完全一致,说明内存内容正确,只是字节序差异导致u32值打印结果不同:
- 若C端按主机字节序写入,Rust直接读取的u32值即为正确值,只是打印视角不同;
- 若C端按网络字节序(大端)写入,Rust需用
u32::from_be_bytes转换:for i in 0..4 { let val = u32::from_be_bytes(x.state[i].to_be_bytes()); println!("{:08x}", val); }
2. 确保结构体布局完全匹配
虽然#[repr(C)]保证Rust结构体遵循C内存布局,仍需确认:
- 成员顺序完全一致:C结构体顺序为
len→state→count,Rust需严格对应(建议把Rust的length改名为len,避免混淆); - 类型完全匹配:
- C的
uint64_t对应Rust的u64(正确); - C的
uint32_t[4]对应Rust的[u32;4](正确); - C的
int对应Rust的libc::c_int(正确,需确保libccrate适配当前平台);
- C的
- 目标平台一致:C和Rust需编译为同一架构(32/64位)、同一操作系统,避免平台差异导致的布局或类型大小变化。
3. 检查C代码是否存在越界写入
如果Rust按字节打印的结果仍和C端不符,需排查C的modify_struct函数是否存在越界写入,比如修改len或count时超出成员内存范围,意外覆盖了state数组内容。
内容的提问来源于stack exchange,提问作者Dillion Nason
相关产品推荐
相关产品推荐

