从Fortran调用C函数,其中C函数名最初是从C传入的
由于不相关的原因,我需要将一个C / C ++函数名称传递给一个Fortran子程序,该子程序又调用该C函数。 我发现我可以成功地将函数名称传递给Fortran子例程。 在那个子程序中,我可以调用正确的C函数。 但是,C函数的参数在此调用中被破坏(当直接从C调用时它工作正常)。 我已经使用ISO C Binding试图让它工作,但无济于事。
这是一个MWE:
fortranRoutine.h:
extern "C" { void fortranRoutine_(void(int status)); };
calledfromFortran.h:
void calledfromFortran(int status);
main.cpp中:
#include "fortranRoutine.h" #include "calledfromFortran.h" using namespace std; int main(int argc, char** argv) { calledfromFortran(12); fortranRoutine_(calledfromFortran); return 0; }
fortranRoutine.f90:
subroutine fortranRoutine(calledfromFortran) use iso_c_binding implicit none interface subroutine calledfromFortran(status) bind (c) use iso_c_binding integer(kind = c_int), intent(in) :: status end subroutine calledfromFortran end interface integer(kind = c_int) :: one one = 2 call calledfromFortran(one) return end subroutine fortranRoutine
calledfromFortran.cpp:
#include #include "stdlib.h" using namespace std; void calledfromFortran(int status) { cout << "In calledfromFortran:" << endl; cout << " status: " << status << endl; }
目前的结果
目前运行这个给出:
In calledfromFortran: status: 12 In calledfromFortran: status: -1641758848
第一次调用来自main
calledfromFortran
工作正常,但是当它从fortranRoutine
调用时,该值被破坏。 请注意,每次运行后一个值都会发生变化。 我究竟做错了什么?
在Fortran和C之间传递标量值时,基本上有两个选项:
-
您通过引用传递它们:在C端,您必须确保使用指向这些标量的指针。
-
您按值传递它们:在Fortran端,您必须确保使用
VALUE
属性,如其他post所建议的那样。
至于intent(in)
属性,它可以保留在那里,因为它不会影响变量是通过值还是引用传递的。 在Fortran中,除非指定VALUE
属性,否则参数始终通过引用传递。 属性intent(in)
仅告诉编译器阻止在例程中使用该伪参数,这将改变其值。
关于命名的附加说明:您应该使用bind(c)
指定Fortran例程fortranRoutine
。 通过这种方式,您可以指定从C中看到的名称,即使它位于模块中:
module my_interface use iso_c_binding contains subroutine fortranRoutine(calledFromFortran) bind(c, name='fortranroutine') ... end subroutine fortranRoutine end module my_interface
这样你可以肯定,从C调用的函数的名称是fortranroutine
,独立于编译器附加下划线,预置模块名称或将名称转换为小写的惯例。 因此,你将在C中有一个头文件,它应该独立地使用编译器 :
extern "C" { void fortranroutine(void(int status)); };
我会将接口定义更改为read
interface subroutine calledfromFortran(status) bind (c) use iso_c_binding integer(kind = c_int), VALUE :: status end subroutine calledfromFortran end interface
我不确定是什么intent(in)
,但是那段代码看起来不正确。 除此之外,其余的看起来(第一次通过)合理而正确。
注意。 ISO C绑定仅在FORTRAN语言的2003版本中添加,因此如果您使用的是旧版本,则可能需要检查编译器文档以获取详细信息。 有些编译器允许ISO C绑定,但可能与我上面显示的略有不同。
编辑。 在查看了intent
关键字之后,您可以尝试将intent(in)
与以下类型声明结合使用,该声明遵循interface
定义
integer (c_int), parameter :: one = 2
我希望这有帮助。