Rust通过FFI调用Fortran库时内存访问违规问题求助
核心问题:参数传递不匹配导致栈布局错乱
你的内存访问错误直接源于Rust代码中数组参数的传递方式错误,以及可能存在的函数名修饰不匹配,和Fortran的1索引特性无关。
具体错误点拆解
数组传递类型错误
Fortran老旧库的数组形参ARRAY(LENGTH)期望接收的是数组首元素的单指针(和VB.net中ByRef ARRAY As Double的传递逻辑一致,VB实际传递的是数组第一个元素的地址)。但你在Rust中传递的是&mut [f64]——这是Rust的胖指针(包含指针+数组长度两个字段,占16字节),而非单指针(8字节)。
这种差异会导致栈上后续参数的位置整体偏移8字节,Fortran读取到的参数值完全错乱:比如原本的LENGTH参数会被替换成切片的长度值,当Fortran尝试将这个数值当作指针去访问内存时,就会出现0x00000079(对应length=121)这类非法地址访问错误。函数名修饰可能不匹配
你使用的_FD_TEMP_DIST@24是32位Windows平台下stdcall调用约定的函数名修饰规则(@24表示参数总字节数),但如果你的运行环境是64位Windows,Fortran库导出的函数名应该是无修饰的FD_TEMP_DIST(64位Windows仅有一种调用约定,无名字修饰后缀)。逻辑参数的潜在类型不匹配
Fortran代码中声明的LOGICAL(4) FLAG是4字节布尔类型,但VB.net用Byte(1字节)适配成功,说明Fortran库导出时将该参数转换成了单字节类型。Rust中用BYTE是正确的,但如果后续仍有问题,可尝试改用i32类型匹配Fortran的LOGICAL(4)。
修正后的Rust代码
use libloading::{library_filename, Library, Symbol}; use std::result::Result; use winapi::shared::minwindef::BYTE; // 替换为你的库文件名(不含后缀) const MODULE: &str = "your_library_name"; pub fn fd_temp_dist( power: f64, mut array: Vec<f64>, length: i32, init_value_a: f64, init_value_b: f64, flag: bool, ) -> Result<(), Box<dyn std::error::Error>> { // 先验证数组长度与传入的length一致,避免Fortran越界 if array.len() != length as usize { return Err("Array length does not match LENGTH parameter".into()); } // 修正函数签名:数组参数用*mut f64(单指针) type FdTempDistFunc = unsafe extern "stdcall" fn( *const f64, // POWER: 传const指针,对应Fortran的传引用 *mut f64, // ARRAY: 数组首指针 *const i32, // LENGTH: 传const指针 *const f64, // INIT_VALUEA *const f64, // INIT_VALUEB *const BYTE, // FLAG ); unsafe { let library = Library::new(library_filename(MODULE))?; // 根据平台选择正确的函数名:64位用b"FD_TEMP_DIST",32位用b"_FD_TEMP_DIST@24" let func: Symbol<FdTempDistFunc> = library.get(b"FD_TEMP_DIST")?; let flag_byte = if flag { 1_u8 } else { 0_u8 }; func( &power, array.as_mut_ptr(), &length, &init_value_a, &init_value_b, &flag_byte, ); Ok(()) } }
额外验证步骤
- 用
dumpbin /exports your_library.dll(Windows)或nm -D your_library.so(Linux)查看库的导出函数名,确认你使用的函数名完全匹配。 - 确保传入的
Vec<f64>长度严格等于length,避免Fortran访问数组时越界。
内容的提问来源于stack exchange,提问作者GreyAerin

