Dav*_*idH 9 c++ fortran optional-parameters fortran-iso-c-binding
如何在使用可选参数的C++头中引用Fortran函数?我可以在标题中为每个可能的呼叫组合设置原型吗?或者这甚至可能吗?
例如,Fortran:
subroutine foo(a, b, c) bind(c)
real, intent(in), optional :: a, b, c
...
end subroutine foo
Run Code Online (Sandbox Code Playgroud)
Vla*_*r F 11
除非你制作子程序,否则至少不可能bind(C).
一旦你完成它bind(C),它只是传递一个指针,它可以在C端为NULL.
subroutine foo(a, b, c) bind(C, name="foo")
real, intent(in), optional :: a, b, c
...
end subroutine foo
Run Code Online (Sandbox Code Playgroud)
(为了real(c_float)从iso_c_binding模块中获得更大的可移植性,应该使用,但这与此问题有些相关)
在C(++)
extern "C"{
void foo(float *a, float *b, float *c);
}
foo(&local_a, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)
然后你可以创建一个C++函数,它调用foo并使用C++风格的可选参数.
关于Fortran与C的进一步互操作性,Fortran在技术规范ISO/IEC TS 29113:2012中允许此功能.
正如Vladimir F 回答的那样,在 Fortran 2018(和 Fortran 2008+TS29113)下,可以optional在 C 互操作 Fortran 过程中使用虚拟参数的属性。
在 Fortran 2008 下这是不可能的。\xc2\xa0 目前有几个编译器不支持此功能。\xc2\xa0 使用这些编译器仍然(尽管需要做更多工作)能够支持“可选”参数。
\n\n问题的过程foo在 F2008 下不是 C 互操作的(即使使用bind(C))。\xc2\xa0 但是,在 F2008 下可以模仿这个想法:有一个 C 互操作过程,type(c_ptr)其参数包装所需的 Fortran 过程。\xc2 \xa0 这个可互操作的包装器可以检查空指针(使用C_ASSOCIATED)以确定是否存在向前传递的参数 - 如果存在则传递取消引用的参数。
例如,带有 C 互操作包装器的 Fortran 端可能看起来像
\n\nmodule mod\n\n use, intrinsic :: iso_c_binding\n\ncontains\n\n subroutine foo_centry(a) bind(c,name=\'foo\')\n type(c_ptr), value :: a\n real(c_float), pointer :: a_pass\n\n nullify(a_pass)\n if (c_associated(a)) call c_f_pointer(a, a_pass)\n call foo(a_pass)\n end subroutine foo_centry\n\n subroutine foo(a)\n real(c_float), optional :: a\n end subroutine foo\n\nend module mod\nRun Code Online (Sandbox Code Playgroud)\n\n在 Fortran 2018 下,我们在互操作接口中具有这种对称性:如果过程是通过 Fortran 以外的方式定义的,但互操作接口有一个可选参数,那么在 F2018 下,我们得到的结果是,在不存在参数的情况下引用此过程意味着空指针被传递给过程。
\n\n在 F2008 下,我们也需要处理这一方面:我们再次使用 F2008 不可互操作过程来做到这一点,该过程用type(c_ptr)参数包装可互操作过程:如果参数存在,则传递其地址;如果存在,则传递其地址;如果存在,则传递其地址。如果没有,则通过C_NULL_PTR。
这样的 F2008 代码可能看起来像
\n\nmodule mod\n use, intrinsic :: iso_c_binding\n\n interface\n subroutine foo_fentry(a) bind(c,name=\'foo\')\n import c_ptr\n type(c_ptr), value :: a\n end subroutine foo_fentry\n end interface\n\ncontains\n\n subroutine foo(a)\n real(c_float), optional, target :: a\n\n if (present(a)) then\n call foo_fentry(c_loc(a))\n else\n call foo_fentry(c_null_ptr)\n end if\n end subroutine foo\n\nend module mod\nRun Code Online (Sandbox Code Playgroud)\n\n请注意由于使用而造成的限制c_loc:在某些情况下,人们可能需要使用副本或采取其他保护措施。