fortran77,iso_c_binding和c字符串 [英] fortran77, iso_c_binding and c string

查看:229
本文介绍了fortran77,iso_c_binding和c字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to call some Fortran77 code from C but I didn't find the proper way of passing a C char array.

   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似乎没有这样的东西.因此,上面的代码无法编译.

This method works with Fortran 90 and target, pointer specifier but Fortran 77 doesn't seems to have such things. So, the code above doesn't compile.

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

The BIND(C) force the parameter c_message to be size 1. How can I access to other elements of the c_message string?

编译器:GCC 4.8.2

Compiler : GCC 4.8.2

推荐答案

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

I am trying to call some Fortran77 code from C but I didn't find the proper way of passing a C char array.

我曾经使用过的所有Fortran 77实现都提供了与C互操作的特定实现机制.通常,这些过程涉及C端了解Fortran编译器采用的名称处理和参数传递约定,并在界面. GCC系统的约定并不难使用.

All Fortran 77 implementations I've ever used have afforded implementation-specific mechanisms for interoperation with C. Generally these involve the C side knowing the name-mangling and argument-passing conventions employed by the Fortran compiler, and using them at the interface. The GCC system's conventions are not that hard to use.

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

You seem to be interested in the Fortran/C interop facility introduced in Fortran 2003, however. Supposing that your Fortran 77 code also conforms with Fortran 2003 (or can be made to do so), it should be possible to write an interoperable wrapper in Fortran 2003. Be aware, however, that the C interop facility does not provide (directly) for interoperability of Fortran variables or subprogram parameters of type character with length greater than 1 or kind different from c_char. On the other hand, keep also in mind that the length of a Fortran character object is not the same thing as the dimension(s) of a character array.

您有几个可互操作的替代方案,它们提供了一个面向C的接口,通过该接口可以接受C char数组.也许最清楚的方法是接受一个Fortran假定大小的character数组:

You have a couple of interoperable alternatives for providing a C-facing interface by which to accept a C char array. Perhaps the clearest one would be to accept a Fortran assumed-size character array:

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的数组指针:

The most likely alternative is to accept C's array pointer directly:

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端数组指针可能为null,则后者是必需的.如果不能依靠数组将其终止为null,则两者都需要传递一个明确的长度.

The latter is necessary if the C-side array pointer might be null. Both require an explicit length to be passed as well if the array cannot be relied upon to be null terminated.

无论如何,如果您最终想要一个长度大于1的Fortran character变量(而不是尺寸大于1的数组),则 interoperable 接口不能提供直接-这些类型不在C interop规定适用的类型中.除非您可以依赖默认字符种类c_char,否则需要将它们与copy-in(/copy-out)结合使用,以便在种类之间转换字符.使用前一个接口,很明显,如何将数组复制到长度大于1的Fortran标量character中.对于指针变量,使用如下所示的转换函数可能会很有用:

In any event, if you ultimately want a Fortran character variable having length greater than 1 (as opposed to an array having dimension greater than 1), then the interoperable interfaces can't provide that directly -- such types are not among those to which the C interop provisions are applicable. Unless you can rely on the default character kind to be c_char, you'll need to couple them with copy-in(/ copy-out) in order to convert the characters between kinds. With the former interface, it should be obvious how you could copy the array to a Fortran scalar character having length greater than 1. For the pointer variant, it might be useful to use a conversion function something like this:

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 C_F_string_ptr子例程)

(Derived from the Fortran Wiki's C_interface_module's C_F_string_ptr subroutine)

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

On the other hand, if you can (or anyway do) rely on the default character kind to be c_char then you have an additional alternative. You can usefully cause a character array such as the parameter in the first example to be associated with a scalar character object of default kind and length greater than one. In particular, if a dummy argument of the wrapped function is a scalar character with assumed length, or with fixed length not exceeding the number of array elements, then you can rely on argument association to associate it with the character array in the wrapper. In other words, in that case you can just pass the array as the actual argument.

这篇关于fortran77,iso_c_binding和c字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆