rust - 为什么对我的 FFI 函数的第二次调用无法匹配字符串比较?

标签 rust ffi unsafe

这段代码显示了从 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 block 的范围。我认为不安全的操作是通过 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");
}

最佳答案

这里使用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;
}

另见:

关于rust - 为什么对我的 FFI 函数的第二次调用无法匹配字符串比较?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56843871/

相关文章:

rust - 我如何使用另一个 crate 中定义的宏?

string - 为什么已转​​换为 char 的字节在推送到字符串时似乎没有正确的类型?

function - rust -将用户提供的安全功能包装到不安全的FFI功能中以进行FFI回调

C# 互操作 : bad interaction between fixed and MarshalAs

c# - 为什么允许从函数内返回不安全的指针?

java - 从未通过 allocateInstance(Java) 从对象调用 Finalize

rust - 为什么我们使用方括号而不是定义它的圆括号来调用 vec 宏?

iterator - 如何为特征实现 "default iterator"?

c++ - 将 Haskell ByteString 转换为 C++ std::string

c - 为什么将堆分配的结构从 Rust 传递到 C 时,我的整数值发生了变化?