为啥我的 FFI 函数的第二次调用无法匹配字符串比较?

Posted

技术标签:

【中文标题】为啥我的 FFI 函数的第二次调用无法匹配字符串比较?【英文标题】:Why does the second call to my FFI function fail to match the string comparison?为什么我的 FFI 函数的第二次调用无法匹配字符串比较? 【发布时间】:2019-07-02 00:21:33 【问题描述】:

这段代码显示了从 Rust 到 Fortran 的 FFI,因为这是我注意到问题的地方,但我很确定这不是 Fortran 特定的,甚至可能与 FFI 无关。

我有 src/main.rs,一个相当小的东西:

extern crate libc;

extern "C" 
    static mut __wrapper_mod_MOD_a_string: [libc::c_char; 30];
    fn __wrapper_mod_MOD_say_hi();


fn main() 
    let s = String::from("hello");
    unsafe  __wrapper_mod_MOD_say_hi() ;

    for i in unsafe  __wrapper_mod_MOD_a_string.iter_mut()  
        *i = ' ' as libc::c_char;
    

    for (i, c) in unsafe  __wrapper_mod_MOD_a_string .iter_mut().zip(s.chars()) 
        *i = c as libc::c_char;
    

    unsafe  __wrapper_mod_MOD_say_hi() ;

    for (i, c) in unsafe  __wrapper_mod_MOD_a_string.iter_mut().zip(s.chars())  
        *i = c as libc::c_char;
    

    unsafe  __wrapper_mod_MOD_say_hi() ;

这会调用 src/wrapper.f90:

module wrapper_mod
   implicit none

   private
   public :: say_hi
   character(30) :: a_string

contains

   subroutine say_hi
      if (trim(a_string) == 'hello') then
         write(6,*) 'Howdy there, partner'
      else
         write(6,*) 'Rude of you not to greet me'
      endif
   end subroutine say_hi
end module wrapper_mod

我得到了输出:

 Rude of you not to greet me
 Rude of you not to greet me
 Howdy there, partner

为什么?最后两行的唯一区别是unsafe 块的范围。我认为不安全的操作是通过 FFI 进行访问,但是一旦我有了一个数组,就可以随意迭代它应该是“安全的”。显然我误解了什么。

我的 Cargo.toml 在 [build-dependencies] 中有 cc = "1.0",并且我有以下 build.rs:

extern crate cc;

fn main() 
    cc::Build::new()
        .file("src/wrapper.f90")
        .compile("libwrapper.a");
    println!("cargo:rustc-link-lib=static=wrapper");
    println!("cargo:rustc-link-lib=dylib=gfortran");

【问题讨论】:

【参考方案1】:

这里使用unsafe 没有什么特别之处。普通花括号也会发生同样的事情:

fn main() 
    let mut bytes = [0; 4];
    let new_bytes = b"demo";

    for (i, &c) in  bytes .iter_mut().zip(new_bytes) 
        *i = c;
    

    println!(":?", bytes);
    // [0, 0, 0, 0]

    for (i, &c) in  bytes.iter_mut().zip(new_bytes)  
        *i = c;
    

    println!(":?", bytes);
    // [100, 101, 109, 111]

使用大括号会强制在大括号内移动变量。由于[libc::c_char; 30][u8; 4] 都实现了Copy,因此由于移动而进行了隐式复制。您可以获取可变引用并将其移动到花括号中:

for (i, &c) in  &mut bytes .iter_mut().zip(new_bytes) 
    *i = c;

另见:

What's the difference between &mut unsafe and unsafe &mut ? Is there a builtin identity function in Rust? Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time Stuff the Identity Function Does (in Rust)

【讨论】:

以上是关于为啥我的 FFI 函数的第二次调用无法匹配字符串比较?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 C++ 中第二次调用析构函数未定义的行为?

仅替换模式中的第二次出现

为啥 Rust 函数和 FFI C++ 函数以相反的顺序执行?

为啥当我第二次使用完全相同的参数调用 IMMUTABLE 函数时,计划时间会加倍?

无法在类内第二次设置字符串类型[关闭]

为啥我的 ViewController 在第二次调用后才发布,iOS ARC?