从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 

我希望这有帮助。