作为Vladimir F answers,在 Fortran 2018(和 Fortran 2008+TS29113)下,可以在 C 互操作 Fortran 过程中将optional 属性用于虚拟参数。
在 Fortran 2008 下这是不可能的。目前仍有几个编译器不支持此功能。使用这些编译器,一个仍然(尽管需要做更多工作)能够支持“可选”参数。
问题的过程foo在F2008下不是C-interoperable(即使是bind(C))。但是,在 F2008 下可以模仿这个想法:有一个带有 type(c_ptr) 参数的 C 互操作过程,它包装了所需的 Fortran 过程。这个可互操作的包装器可以检查空指针(使用C_ASSOCIATED)以确定是否存在向前传递的参数 - 如果存在则传递取消引用的参数。
例如,带有 C 互操作包装器的 Fortran 端可能看起来像
module mod
use, intrinsic :: iso_c_binding
contains
subroutine foo_centry(a) bind(c,name='foo')
type(c_ptr), value :: a
real(c_float), pointer :: a_pass
nullify(a_pass)
if (c_associated(a)) call c_f_pointer(a, a_pass)
call foo(a_pass)
end subroutine foo_centry
subroutine foo(a)
real(c_float), optional :: a
end subroutine foo
end module mod
在 Fortran 2018 下,我们在互操作接口中具有这种对称性:如果过程是通过 Fortran 以外的方式定义的,但互操作接口有一个可选参数,那么在 F2018 下,我们会得到结果,即使用不存在的参数引用此过程表示将空指针传递给过程。
在 F2008 下,我们也需要处理这方面:我们再次使用 F2008 不可互操作过程来处理,该过程使用type(c_ptr) 参数包装可互操作过程:如果参数存在,则传递其地址;如果没有,请通过C_NULL_PTR。
这样的 F2008 代码可能看起来像
module mod
use, intrinsic :: iso_c_binding
interface
subroutine foo_fentry(a) bind(c,name='foo')
import c_ptr
type(c_ptr), value :: a
end subroutine foo_fentry
end interface
contains
subroutine foo(a)
real(c_float), optional, target :: a
if (present(a)) then
call foo_fentry(c_loc(a))
else
call foo_fentry(c_null_ptr)
end if
end subroutine foo
end module mod
请注意此处使用c_loc 造成的限制:在某些情况下,可能需要使用副本或采取其他保护措施。