从c++调用带有可选参数的Fortran子程序
Calling Fortran subroutines with optional arguments from C++
我如何在使用可选参数的c++头文件中引用Fortran函数?我是否有一个原型在头为每个可能的组合调用?或者这可能吗?
例如,Fortran:
subroutine foo(a, b, c) bind(c)
real, intent(in), optional :: a, b, c
...
end subroutine foo
这是不可能的,至少是可移植的,除非您使子程序bind(C)
。
一旦你把它设置为bind(C)
,它只是传递一个指针,在C端可以是NULL。
subroutine foo(a, b, c) bind(C, name="foo")
use iso_c_binding, only: c_float
real(c_float), intent(in), optional :: a, b, c
...
end subroutine foo
(为了更好的可移植性,我使用了iso_c_binding
模块中的real(c_float)
,但这与这个问题有些无关)
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的进一步互操作性,后来被纳入Fortran 2018。
作为Vladimir F回答,在Fortran 2018(和Fortran 2008+TS29113)下,可以在C可互操作的Fortran过程中使用optional
属性作为虚拟参数。
在Fortran 2008下这是不可能的。一些编译器目前仍不支持此特性。使用这些编译器,仍然可以(尽管需要更多的工作)支持"可选"参数。
问题的过程foo
在F2008下不能与c互操作(即使与bind(C)
)。然而,在F2008下模仿这个想法是可能的:用type(c_ptr)
参数包装所需的Fortran过程,有一个c可互操作的过程。这个可互操作的包装器可以检查空指针(使用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
所造成的限制:在某些情况下,可能需要使用副本或采取其他保护措施。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- 如何使用 std::vector 作为参数调用 Fortran 77 C++函数?
- Fortran 的参数语句是否与 C/C++ 的 #define 语句相似?
- 如何在C语言中以函数作为参数调用Fortran dll
- 从c++调用带有可选参数的Fortran子程序