如何在Rust FFI中正确解析数组类型参数?我的实现解析失败
Rust FFI 数组参数解析错误的修复方案
问题根源
你定义的FfiArray是C风格的数组元组结构体(包含数据指针和长度),但Node.js端直接传递了DoubleArray类型——这是把数组的原始内存直接传给Rust,和Rust期望的结构体内存布局完全不匹配。所以Rust会把数组第一个元素的二进制值(1.2的IEEE754表示0x3ff3333333333333)当成data指针,把后续内存里的随机值当成len,导致解析完全错误。
修复步骤
1. 统一两端的参数类型(Node.js端)
在Node.js里定义和RustFfiArray完全对应的C结构体,手动传入数组的指针和长度:
import ffi from "ffi-napi"; import ref from "ref-napi"; import ref_struct from "ref-struct-di"; const StructType = ref_struct(ref); // 定义和Rust FfiArray完全匹配的C结构体 const FfiArray = StructType({ data: ref.refType(ref.types.double), // 对应Rust的*const f64 len: ref.types.size_t // 对应Rust的usize }); const libm = ffi.Library("./target/release/wave_from_tools.dll", { my_push: ["void", [FfiArray]] // 参数类型改为自定义的FfiArray结构体 }); // 创建测试数组,需确保数组在函数调用期间不会被GC回收 const testArr = new Float64Array([1.2, 2.2]); // 包装成FfiArray结构体 const ffiArr = new FfiArray(); ffiArr.data = testArr.buffer; ffiArr.len = testArr.length; libm.my_push(ffiArr);
2. 完善Rust端的slice转换(可选但推荐)
在Rust函数里把FfiArray转换成安全的&[f64]切片,方便后续处理:
use safer_ffi::{prelude::*}; #[derive_ReprC] #[repr(C)] #[derive(Debug)] pub struct FfiArray<'a> { pub data: *const f64, pub len: usize, _marker: std::marker::PhantomData<&'a [f64]>, } #[ffi_export] pub fn my_push(array: FfiArray) { // 转换成安全切片,需确保data指针有效且len正确 let slice = unsafe { std::slice::from_raw_parts(array.data, array.len) }; println!("my_push: 数组内容: {:?}, 长度: {}", slice, array.len); }
3. 复杂结构体数组的扩展(针对[{ idx: 2, name: "test_name" }]场景)
如果要传递自定义结构体数组,步骤类似:
- Rust端定义带
#[derive_ReprC]的结构体 - Node.js端定义对应的结构体类型,再创建结构体数组,最后包装成
FfiArray传递
示例Rust代码:
#[derive_ReprC] #[repr(C)] #[derive(Debug)] pub struct FfiItem { pub idx: u32, pub name: *const c_char, // 用C风格字符串传递文本 } #[derive_ReprC] #[repr(C)] #[derive(Debug)] pub struct FfiItemArray<'a> { pub data: *const FfiItem, pub len: usize, _marker: std::marker::PhantomData<&'a [FfiItem]>, }
Node.js端对应定义结构体后,即可按同样逻辑创建数组并传递。
关键注意事项
- 内存安全:确保Node.js传递的数组在Rust函数执行期间不会被JavaScript引擎GC回收,避免悬垂指针。
- 类型匹配:两端的结构体字段类型、顺序必须完全一致,否则会出现内存解析错位。
- 字符串处理:传递字符串时需用C风格的
const char*(Rust用safer_ffi::str::CStr),不能直接传JavaScript字符串。
内容的提问来源于stack exchange,提问作者tomato
相关产品推荐
相关产品推荐

