fortran77,iso_c_binding和c string

时间:2016-12-20 16:43:03

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

我试图从C调用一些Fortran77代码,但我没有找到传递C char数组的正确方法。

   SUBROUTINE My_F_Code (c_message)  BIND(C, NAME='my_f_code')
     USE ISO_C_BINDING
     IMPLICIT NONE
     CHARACTER*(C_CHAR)      c_message
     CHARACTER*(256)         f_message
     CALL C_F_POINTER( C_LOC(c_message), f_message)
     WRITE(*,*) f_message,LEN(f_message)
   END

此方法适用于Fortran 90和目标,指针说明符,但Fortran 77似乎没有这样的东西。所以,上面的代码没有编译。

BIND(C)强制参数c_message为大小1.如何访问c_message字符串的其他元素?

编译:GCC 4.8.2

2 个答案:

答案 0 :(得分:3)

  

我试图从C调用一些Fortran77代码,但是我找不到传递C char数组的正确方法。

我曾经使用的所有Fortran 77实现都提供了与C互操作的特定于实现的机制。通常这些涉及C端知道Fortran编译器使用的名称修改和参数传递约定,并在接口。海湾合作委员会制度的惯例并不难以使用。

然而,您似乎对Fortran 2003中引入的Fortran / C互操作工具感兴趣。假设您的Fortran 77代码也符合Fortran 2003(或者可以这样做),应该可以在Fortran 2003中编写可互操作的包装器。但是,请注意,C interop工具不提供(直接)对于长度大于1或与character不同的Fortran变量或类型c_char的子程序参数的互操作性。另一方面,请记住Fortran角色对象的 length 与字符数组的 dimension 不同。

您有几个可互操作的替代方案,用于提供接受C char数组的面向C的接口。也许最明显的是接受Fortran假定大小的character数组:

SUBROUTINE My_F_Code (c_message)  BIND(C, NAME='my_f_code')
    USE ISO_C_BINDING
    IMPLICIT NONE
    CHARACTER(kind=C_CHAR), dimension(*), intent(in) :: c_message
    ! ...
END

最可能的选择是直接接受C的数组指针:

SUBROUTINE My_F_Code (c_message)  BIND(C, NAME='my_f_code')
    USE ISO_C_BINDING
    IMPLICIT NONE
    type(C_PTR), value :: c_message
    ! ...
END

如果C端数组指针可能为空,则后者是必需的。如果不能依赖数组作为空终止,则两者都需要传递显式长度。

无论如何,如果你最终想要一个长度大于1的Fortran character变量(而不是一个维度大于1的数组),那么可互操作的接口可以' t直接提供 - 这些类型不属于C互操作规定适用的类型。除非您可以依赖默认字符种类c_char,否则您需要将它们与copy-in(/ copy-out)结合起来才能转换种类之间的字符。使用前一个接口,应该很清楚如何将数组复制到长度大于1的Fortran标量character。对于指针变体,使用这样的转换函数可能很有用:

subroutine C_string_ptr_to_F_string(C_string, F_string)
    use ISO_C_BINDING
    type(C_PTR), intent(in) :: C_string
    character(len=*), intent(out) :: F_string
    character(len=1, kind=C_CHAR), dimension(:), pointer :: p_chars
    integer :: i
    if (.not. C_associated(C_string)) then
      F_string = ' '
    else
      call C_F_pointer(C_string, p_chars, [huge(0)])
      do i = 1, len(F_string)
        if (p_chars(i) == C_NULL_CHAR) exit
        F_string(i:i) = p_chars(i)
      end do
      if (i <= len(F_string)) F_string(i:) = ' '
    end if
end subroutine

(源自Fortran Wiki的C_interface_moduleC_F_string_ptr子程序)

另一方面,如果你可以(或者总是)依赖默认字符种类c_char,那么你还有另外一种选择。您可以有用地使第一个示例中的参数等字符数组与默认类型和长度大于1的标量字符对象相关联。特别是,如果包装函数的伪参数是具有假定长度的标量字符,或者固定长度不超过数组元素的数量,则可以依赖参数关联将其与包装器中的字符数组相关联。换句话说,在这种情况下,您只需将数组作为实际参数传递。

答案 1 :(得分:-1)

  SUBROUTINE FCODE(STR, N)
  CHARACTER*(*) STR
  INTEGER N
  WRITE(*,*), STR, N
  END


  void foo(char *str)
  {
      int N = 10;
      printf("Calling fortran\n");
      fcode_(str,  &N, strlen(str)); 
  }

您需要将sgtring长度作为隐藏参数传递。     在这里看我的文章    http://www.malcolmmclean.site11.com/www/MpiTutorial/CandFortran77.html