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

   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_消息的大小为1。如何访问c U消息字符串的其他元素?
编译器:GCC 4.8.2

最佳答案

我正试图从C调用一些Fortran77代码,但我没有找到传递C字符数组的正确方法。
我使用过的所有Fortran 77实现都提供了与C互操作的特定于实现的机制。通常,这些机制包括C端知道Fortran编译器使用的名称管理和参数传递约定,并在接口上使用它们。GCC系统的约定并不难使用。
不过,您似乎对Fortran 2003中引入的Fortran/C互操作功能感兴趣。假设您的Fortran 77代码也符合Fortran 2003(或者可以这样做),那么应该可以在fortran2003中编写一个可互操作的包装器。但是,请注意,C interop工具没有(直接)为长度大于1或不同于character的Fortran变量或c_char类型的子程序参数提供互操作性。另一方面,还要记住Fortran字符对象的长度与字符数组的维数不同。
您有两个可互操作的替代方案来提供面向C的接口,通过该接口可以接受Cchar数组。也许最清楚的方法是接受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的Fortrancharacter变量(而不是一个维度大于1的数组),那么可互操作的接口就不能直接提供这种类型——这些类型不属于C interop规定适用的类型。除非可以将默认字符类型设置为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_module'sC_F_string_ptr子例程)
另一方面,如果您可以(或者无论如何)依赖于默认字符类型c_char,那么您还有另外一个选择。可以有效地使字符数组(如第一个示例中的参数)与默认类型和长度大于1的标量字符对象相关联。特别是,如果包装函数的伪参数是具有假定长度的标量字符,或具有不超过数组元素数的固定长度,则可以依赖参数关联将其与包装中的字符数组关联。换句话说,在这种情况下,可以将数组作为实际参数传递。

08-07 14:01
查看更多