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

时间:2016-10-17 14:51:40

标签: c++ fortran optional-parameters fortran-iso-c-binding

如何在使用可选参数的C ++头中引用Fortran函数?我可以在标题中为每个可能的呼叫组合设置原型吗?或者这甚至可能吗?

例如,Fortran:

@Singleton
@Startup
public class DirBean implements TimedObject {

  @Resource
  protected TimerService timer;

  @PostConstruct
  public void init() {
    // some code I don't want to run
  }

  public void methodIwantToTest() {
     // test this code
  }
}

2 个答案:

答案 0 :(得分:10)

除非你制作子程序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

(应该使用来自real(c_float)模块的更高可移植性iso_c_binding,但这与此问题有些相似)

在C(++)

extern "C"{
  void foo(float *a, float *b, float *c);
}

foo(&local_a, NULL, NULL);

然后你可以创建一个C ++函数,它调用foo并使用C ++风格的可选参数。

Fortran在技术规范ISO / IEC TS 29113:2012中允许使用此功能,以了解Fortran与C的进一步互操作性。

答案 1 :(得分:1)

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

在Fortran 2008中是不可能的。目前仍有几个编译器不支持此功能。有了这些编译器,一个(尽管还有更多工作)仍然能够支持“可选”参数。

在F2008下,问题的过程foo不可C互操作(即使使用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所造成的限制:在某些情况下,您可能想使用副本或采取其他保护措施。