使用C++中的可选参数调用Fortran子例程

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中允许此功能.


fra*_*lus 6

正如Vladimir F 回答的那样,在 Fortran 2018(和 Fortran 2008+TS29113)下,可以optional在 C 互操作 Fortran 过程中使用虚拟参数的属性。

\n\n

在 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)以确定是否存在向前传递的参数 - 如果存在则传递取消引用的参数。

\n\n

例如,带有 C 互操作包装器的 Fortran 端可能看起来像

\n\n
module 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\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

在 Fortran 2018 下,我们在互操作接口中具有这种对称性:如果过程是通过 Fortran 以外的方式定义的,但互操作接口有一个可选参数,那么在 F2018 下,我们得到的结果是,在不存在参数的情况下引用此过程意味着空指针被传递给过程。

\n\n

在 F2008 下,我们也需要处理这一方面:我们再次使用 F2008 不可互操作过程来做到这一点,该过程用type(c_ptr)参数包装可互操作过程:如果参数存在,则传递其地址;如果存在,则传递其地址;如果存在,则传递其地址。如果没有,则通过C_NULL_PTR

\n\n

这样的 F2008 代码可能看起来像

\n\n
module 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\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意由于使用而造成的限制c_loc:在某些情况下,人们可能需要使用副本或采取其他保护措施。

\n