使用safer-ffi生成Rust DLL,ffi-napi调用结构体参数异常排查
问题:Rust safer-ffi生成的DLL中结构体参数在Node.js ffi-napi调用时乱码
我用Rust的safer-ffi库编译生成DLL,其中process_waave_info函数接收自定义WavesInfo结构体作为参数,但通过Node.js的ffi-napi调用该函数时,结构体字段值出现乱码,无法正确传递参数。同一DLL中的get_sens_to_px函数(仅接收基础类型参数)调用完全正常。
代码片段
Rust 代码(lib.rs)
use safer_ffi::prelude::*; #[ffi_export] #[derive_ReprC] #[repr(C)] pub struct WavesInfo { pub wave_count: u32, pub wave_heights: *const f32, pub wave_periods: *const f32, } #[ffi_export] pub fn process_waave_info(info: WavesInfo) -> u32 { println!("Received wave_count: {}", info.wave_count); println!("First wave height: {}", unsafe { *info.wave_heights }); println!("First wave period: {}", unsafe { *info.wave_periods }); info.wave_count } #[ffi_export] pub fn get_sens_to_px(sens: f32) -> f32 { sens * 100.0 } safer_ffi::cfg_aliases! { #[cfg(target_os = "windows")] OS_WINDOWS = true; } #[cfg(OS_WINDOWS)] #[ffi_export] pub extern "C" fn DllMain(_: HINSTANCE, call_reason: DWORD, _: LPVOID) -> BOOL { match call_reason { DLL_PROCESS_ATTACH => println!("DLL loaded"), DLL_PROCESS_DETACH => println!("DLL unloaded"), _ => (), } TRUE }
Node.js 代码(test.mjs)
import ffi from 'ffi-napi'; import ref from 'ref-napi'; import refArray from 'ref-array-napi'; const f32Array = refArray(ref.types.float); const WavesInfo = ref.types.struct({ wave_count: ref.types.uint32, wave_heights: f32Array, wave_periods: f32Array, }); const lib = ffi.Library('./target/release/wave_processor.dll', { process_waave_info: ['uint32', [WavesInfo]], get_sens_to_px: ['float', ['float']], }); // 测试get_sens_to_px(正常工作) const sensResult = lib.get_sens_to_px(0.5); console.log('get_sens_to_px result:', sensResult); // 输出: get_sens_to_px result: 50 // 测试process_waave_info(结构体参数乱码) const waveHeights = new f32Array([1.2, 3.4, 5.6]); const wavePeriods = new f32Array([6.0, 7.0, 8.0]); const wavesInfo = new WavesInfo({ wave_count: 3, wave_heights: waveHeights, wave_periods: wavePeriods, }); const result = lib.process_waave_info(wavesInfo); console.log('process_waave_info result:', result);
错误输出与期望输出
当前错误输出
DLL loaded get_sens_to_px result: 50 Received wave_count: 1869576192 First wave height: 0.0 First wave period: 0.0 process_waave_info result: 1869576192
期望输出
DLL loaded get_sens_to_px result: 50 Received wave_count: 3 First wave height: 1.2 First wave period: 6.0 process_waave_info result: 3
排查与解决方案
核心原因:结构体类型定义不匹配
问题出在Node.js中WavesInfo结构体的类型定义与Rust侧的C兼容结构体不匹配:
- 指针类型处理错误:Rust侧的
wave_heights和wave_periods是*const f32(对应C的const float*),但Node.js中直接用f32Array类型会传递数组对象的包装结构,而非原始指针地址,导致Rust读取到错误内存值。 - 内存布局不兼容:
ref-array-napi生成的数组类型包含元数据(如长度),而非单纯的指针,破坏了结构体的C语言内存布局。
修正后的Node.js代码
import ffi from 'ffi-napi'; import ref from 'ref-napi'; // 正确对应Rust的*const f32:C语言的const float* const floatPtr = ref.types.pointer(ref.types.float); const WavesInfo = ref.types.struct({ wave_count: ref.types.uint32, wave_heights: floatPtr, wave_periods: floatPtr, }); const lib = ffi.Library('./target/release/wave_processor.dll', { process_waave_info: ['uint32', [WavesInfo]], get_sens_to_px: ['float', ['float']], }); // 测试正常函数 const sensResult = lib.get_sens_to_px(0.5); console.log('get_sens_to_px result:', sensResult); // 修正结构体参数传递 const waveHeights = ref.alloc('float', 3); ref.writeFloat(waveHeights, 0, 1.2); ref.writeFloat(waveHeights, 4, 3.4); // float占4字节,偏移量4 ref.writeFloat(waveHeights, 8, 5.6); const wavePeriods = ref.alloc('float', 3); ref.writeFloat(wavePeriods, 0, 6.0); ref.writeFloat(wavePeriods, 4, 7.0); ref.writeFloat(wavePeriods, 8, 8.0); const wavesInfo = new WavesInfo({ wave_count: 3, wave_heights: waveHeights, wave_periods: wavePeriods, }); const result = lib.process_waave_info(wavesInfo); console.log('process_waave_info result:', result);
额外注意事项
- 内存生命周期:确保Node.js侧分配的数组内存在Rust函数执行期间有效,若Rust需要长期持有指针,需在Rust侧复制数据。
- ReprC验证:Rust结构体必须添加
#[derive_ReprC]和#[repr(C)],保证内存布局与C语言完全一致。 - 调用约定:safer-ffi默认使用
extern "C",ffi-napi默认也是C调用约定,无需额外配置,若有改动需保持一致。
内容的提问来源于stack exchange,提问作者tomato
相关产品推荐
相关产品推荐

