Почему второй вызов моей функции FFI не соответствует сравнению строк? - PullRequest
3 голосов
/ 02 июля 2019

Этот код показывает FFI от Rust до Fortran, потому что именно там я заметил проблему, но я уверен, что это не специфично для 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 есть cc = "1.0" в [build-dependencies], и у меня есть следующий 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 Ответ

4 голосов
/ 02 июля 2019

Здесь нет ничего особенного в использовании 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;
}

Смотри также:

...