我有一些 fortran 测试,我想使用 create_test_sourcelist 在 CTest 中运行。这是一个在 C 或 C++ 中创建驱动程序的实用程序,它调用 fortran 测试例程并期望签名:
int fortname(int argv, char** argc)
有人可以解释连接此签名的正确方法,可能是 iso_c_bindings,据我了解,这些都变得非常标准。我相信是 char** 让我受伤了——整数参数有很多例子。
谢谢!
假设 argc 和 argv 在 C 程序的 main 函数上下文中的含义适用,那么您可以执行以下操作:
! Default binding label is already lower case, but for clarity
! it is good practice to specify the binding label explicitly.
function fortname(argc, argv) bind(c, name='fortname')
use, intrinsic :: iso_c_binding, only: c_int, c_ptr
implicit none
!----
! Note C std allows argc == 0
integer(c_int), intent(in), value :: argc
! Lower bound set to match C convention where element 0 probably
! is name of program. May be zero size.
type(c_ptr), intent(in) :: argv(0:argc-1)
! Function result.
integer(c_int) :: fortname
将这些参数转换为更易于在 Fortran 中使用的参数(并进一步假设您的 Fortran 处理器支持 Fortran 2003 标准的所有适用部分,请注意至少一个常用处理器目前不支持延迟长度字符组件)那你可以...
!----
! Name of the program.
character(:), allocatable :: prog_name
! Type to use for arrays of pointers to variable length strings.
type :: string
character(:), allocatable :: item
end type string
! Our arguments. May be zero size.
type(string) :: arguments(argc-1)
integer :: i ! argument index.
!****
if (argc > 0) then ! argv has something useful
! make program name accessible to fortran code.
call c_f_string(argv(0), prog_name)
! make arguments accessible to fortran code.
do i = 1, size(arguments)
call c_f_string(argv(i), arguments(i)%item)
end do
else ! no useful information provided in argv
prog_name = ''
end if
! Work with arguments%item and prog_name...
print "(A)", prog_name
do i = 1, size(arguments) ; print "(A)", arguments(i)%item ; end do
fortname = 0
contains
! Copy a null terminated C string (specified via a non-null c_ptr) to an
! allocatable deferred length default character variable.
subroutine c_f_string(c_string, f_string)
use, intrinsic :: iso_c_binding, only: c_char, c_null_char, c_f_pointer
!----
type(c_ptr), intent(in) :: c_string
character(:), intent(out), allocatable :: f_string
!----
! Array for accessing string pointed at by C pointer
character(kind=c_char), pointer :: string_ptr(:)
integer :: i ! string index
interface
! Steal std C library function rather than writing our own.
function strlen(s) bind(c, name='strlen')
use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t
implicit none
!----
type(c_ptr), intent(in), value :: s
integer(c_size_t) :: strlen
end function strlen
end interface
!****
! Map C pointer to fortran character array
call c_f_pointer(c_string, string_ptr, [strlen(c_string)])
! Allocate fortran character variable to the c string's length
allocate(character(size(string_ptr)) :: f_string)
! Copy across (with possible kind conversion) characters
forall (i = 1:size(string_ptr)) f_string(i:i) = string_ptr(i)
end subroutine c_f_string
end function fortname
您的 fortran 声明将是这样的(我认为您弄混了argc
,argv
所以我交换了它们):
function fortname(argc, argv) bind(c)
use iso_c_binding
integer(c_int), value :: argc
type(c_ptr) :: argv
end function
然后,您需要编写一些代码来转换argc
为 fortran 类型。您可以使用 instrinsic 将 c 指针转换为 fortran 指针c_f_ptr
。棘手的一点是你有双重间接,因为fortran不支持指针指针的概念。可能以下方法会起作用,它会打印出每个参数
type(c_ptr), pointer :: argv_f
character(c_char), pointer :: string_n
call c_f_ptr(argv, argv_f)
do n=1,argc
call_c_f_ptr(argvf(n), string_n)
print *, string_n
end do
免责声明:我尚未编译或运行此代码!