字符串的C和Fortran互操作性
我试图从C中调用一些Fortran代码,但没有找到传递C字符数组的正确方法字符串的C和Fortran互操作性,c,arrays,fortran,fortran-iso-c-binding,C,Arrays,Fortran,Fortran Iso C Binding,我试图从C中调用一些Fortran代码,但没有找到传递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(
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
BIND(C)
强制参数C_消息的大小为1。如何访问c_消息字符串的其他元素
编译器:GCC4.8.2
我试图从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 77实现都为与C的互操作提供了特定于实现的机制。通常,这些机制涉及C端了解Fortran编译器使用的名称混乱和参数传递约定,并在接口处使用它们。GCC系统的约定并不难使用
不过,您似乎对Fortran 2003中引入的Fortran/C互操作功能感兴趣。假设您的Fortran 77代码也符合Fortran 2003(或者可以这样做),那么应该可以在Fortran 2003中编写一个可互操作的包装器。但是,请注意,C interop功能不能(直接)提供Fortran变量或长度大于1或与C_char不同类型的character
类型的子程序参数的互操作性。另一方面,请记住Fortran字符对象的长度与字符数组的维数不同
您有两个可互操作的备选方案来提供面向C的接口,通过该接口可以接受Cchar
数组。也许最清楚的方法是接受Fortran假定的大小字符
数组:
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端数组指针可能为空,则必须使用后者。如果不能依赖数组以null结尾,则两者都需要传递显式长度
在任何情况下,如果您最终想要一个长度大于1的Fortran字符
变量(与维数大于1的数组相反),那么可互操作接口不能直接提供这一点——此类类型不属于C互操作规定适用的类型。除非您可以依赖默认字符种类为c_char
,否则您需要将它们与copy-in(/copy-out)耦合,以便在种类之间转换字符。使用前一个接口,很明显可以将数组复制到长度大于1的Fortran标量字符。对于指针变量,可以使用如下转换函数:
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
子程序C_字符串\u ptr_到F_字符串(C_字符串,F_字符串)
使用ISO_C_绑定
类型(C_PTR),意图(in)::C_字符串
字符(len=*),意图(out)::F_字符串
字符(len=1,kind=C_字符),维度(:),指针::p_字符
整数::i
如果(.not.C_关联(C_字符串)),则
F_字符串=“”
其他的
调用C_F_指针(C_字符串,p_字符,[大(0)])
i=1,len(F_字符串)
如果(p_chars(i)=C_NULL_CHAR)退出
F_字符串(i:i)=p_字符(i)
结束
如果(i)
您需要将sgtring length作为隐藏参数传递。
请看我的文章
我很困惑。Fortran 77(和Fortran 90)没有F2K C互操作功能。您的代码Fortran 77是以什么方式编写的?我也很困惑。Gfortran将代码编译为Fortran 2008和绑定(C)
接口是Fortran 2003。您必须显示正在接口的子例程和收到的错误消息。这非常重要。例如,字符*(C\u CHAR)
在语法上不正确。您应该只使用字符(kind=C\u CHAR)
并且不关心您的代码是F77还是F。大多数Fortran 77代码都是有效的Fortran 2008代码。您是对的,gfortran使用的是f2008标准,没有与f95标准的ISO_C_绑定给定的代码假定Fortran编译器以特定的方式(小写,尾随下划线)装饰其符号。这种约定远不是普遍存在的。隐藏字符长度的约定可能也会有所不同。它们确实有所不同。在gfortran中将其从int更改为size\t的修补程序已经准备就绪。我假设大量使用类似代码的无知询问者涌入。关于最后一段,只有在需要进行种类转换时才需要副本需要。如果需要,C_CHAR类型的延迟长度指针可以与C字符串占用的相同存储序列相关联。通过简单检查,wiki页面不使用延迟长度字符,可能是因为编写时缺少gfortran支持。@IanH,感谢您的观察。我已经修改了编辑并扩展了我的评论,以讨论关联而不是复制,这确实是在可能的情况下更可取的做法。