【问题标题】:How to receive a string from a C function called by Fortran by iso_c_binding?如何通过iso_c_binding从Fortran调用的C函数接收字符串?
【发布时间】:2019-12-09 10:47:25
【问题描述】:

我想从 Fortran 调用 C 函数并接收 C 函数中定义的字符串。我进行了搜索,但到目前为止我找不到一个可行的、直接的答案。

其实我找到了一种解决方法:改为接收一个字符数组,然后使用内部函数transfer 将结果放入 Fortran 字符串中。 这是我的工作代码。

Fortran 主程序:

program pr
    implicit none
    character(200) :: stringa

    call strfromc(stringa)
    write (6,*) 'FPR stringa: "', trim(stringa),'"'

    stop
end program pr

Fortran 子程序:

subroutine strfromc(stringa)
    use iso_c_binding
    implicit none

    character(200) :: stringa

    interface
        subroutine getstrfromc(ld,d) bind(c,name='getString')
            import :: c_int, c_ptr
            integer(c_int) :: ld
            type(c_ptr), value :: d
        end subroutine getstrfromc
    end interface

    ! declare a character array of type c_char and sufficient length:
    character(c_char), dimension(200), target :: d1

    integer :: ld1 ! will contain the string length
    integer :: i

    ! the C pointer of character array d1 is passed:
    call getstrfromc(ld1, c_loc(d1))

    ! read the first ld1 elements of array d1 as a character string, which will be returned:
    stringa= transfer(d1(1:ld1), stringa)

    write (6,*) 'SF d1: ', (d1(i),i=1,ld1)
    write (6,*) 'SF stringa: "', trim(stringa),'"'
    write (6,*) ''

    return
end subroutine

C 函数:

#include <stdio.h>
#include <string.h>

void getString(int * lw, char * w) {
    printf("Enter a string:\n");
    scanf("%[^\n]", w); //scanning the whole string, including the white spaces

    *lw= strlen(w);

    printf("C: w: %s\n", w);
    printf("C: lw: %d\n", *lw);
    printf("\n");

    return;
}

谁能提出更直接的方法?

【问题讨论】:

  • 您知道character(len=200) a 的实际实参可以是与character(len=1) b(*)(或b(200))哑元关联的实参吗?
  • @francescalus 我需要 d1 成为“目标”。我尝试将它用作虚拟参数,编译器说我需要子程序 strfromc 的显式接口
  • 是的,如果您有带有目标虚拟参数的strfromc,您将需要该子例程来拥有主程序的显式接口。如果你给它一个(比如把strfromc放在一个使用的模块中),那么它会起作用吗?
  • 是的,确实如此,谢谢!我在“答案”中发布了我的新代码。

标签: c string fortran fortran-iso-c-binding


【解决方案1】:

为什么不简单地使用C_CHAR kind?我稍微“压缩”了你的代码:

program main
  use, intrinsic :: iso_c_binding, only: C_INT, C_CHAR
  implicit none
  integer         :: lw ! will contain the string length
  character(256)  :: w = "" ! will contain the string; Initialize to empty

  ! C interface
  interface
    subroutine getstrfromc( lw, w ) bind( c, name='getString' )
      import :: C_INT, C_CHAR
      implicit none
      integer(C_INT), intent(out)     :: lw
      character(C_CHAR), intent(out)  :: w(*)
    end subroutine getstrfromc
  end interface

  ! In Fortran variables are passed by default as "pointers".
  call getstrfromc( lw, w )

  ! Write string
  write (*,*) "Fortran: w: ", trim(w)
  write (*,*) "Fortran: lw:", lw

end program main

C 函数保持不变。

【讨论】:

  • 是的!谢谢! ...现在我将研究并找出为什么我早期使用 c_char 的尝试没有奏效...再次感谢您!
  • 如果你想把它作为一个函数来做stackoverflow.com/questions/69126800/….f90 btw
【解决方案2】:

我将其发布在答案中,因为它看起来更干净。 这是我根据@francescalus 的建议修改的代码。

Fortran 主程序:

program pr
    use sfc
    implicit none
    character(200) :: stringa

    call strfromc(stringa)
    write (6,*) 'FPR stringa: "', trim(stringa),'"'

    stop
end program pr

Fortran 模块,包括 C 函数和 Fortran 子程序的接口:

module sfc
    use iso_c_binding
    implicit none

    interface
        subroutine getstrfromc(ld,d) bind(c,name='getString')
            import :: c_int, c_ptr
            integer(c_int) :: ld
            type(c_ptr), value :: d
        end subroutine getstrfromc
    end interface

contains

subroutine strfromc(d1)
    use iso_c_binding
    implicit none

    ! declare a character array of type c_char and sufficient length:
    character(c_char), dimension(200), target :: d1

    integer :: ld1 ! will contain the string length
    integer :: i


    ! the C pointer of character array d1 is passed:
    call getstrfromc(ld1, c_loc(d1))

    ! clean elements after the ld1-th:
    d1(ld1+1:)= ''

    write (6,*) 'SF d1: ', (d1(i),i=1,ld1)
    write (6,*) ''

    return
end subroutine

end module sfc

C 函数保持不变。

...其他建议?!?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 2017-07-20
    • 1970-01-01
    相关资源
    最近更新 更多