2

由于不相关的原因,我需要将 C/C++ 函数名称传递给 Fortran 子例程,该子例程又调用该 C 函数。我发现我可以成功地将函数名传递到 Fortran 子例程中。在那个子程序中,我可以调用正确的 C 函数。但是,C 函数的参数在此调用中被破坏(当直接从 C 调用时,它工作正常)。我已经使用ISO C Binding来尝试让它工作,但无济于事。

这是一个MWE:

fortranRoutine.h:

extern "C" {
    void fortranRoutine_(void(int status));
};

从Fortran.h调用:

void calledfromFortran(int status);

主.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

从Fortran.cpp 调用:

#include <iostream>
#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

calledfromFortran对from的第一次调用可以main正常工作,但是从fortranRoutine值调用它时会被破坏。请注意,每次运行时,后一个值都会发生变化。我究竟做错了什么?

4

2 回答 2

3

在 Fortran 和 C 之间传递标量值时,基本上有两种选择:

  • 您通过引用传递它们:在 C 端,您必须确保使用指向这些标量的指针。

  • 您按值传递它们:在 Fortran 方面,您必须确保使用该VALUE属性,正如其他帖子已经建议的那样。

至于intent(in)属性,它可以留在那里,因为它不影响变量是通过值传递还是引用传递。VALUE在 Fortran 中,除非您指定属性,否则参数始终通过引用传递。该属性intent(in)仅告诉编译器防止在例程中使用该虚拟参数,这将改变其值。

关于命名的附加说明:您fortranRoutine还应该使用bind(c). 通过这种方式,您可以指定它的名称,如从 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));
};
于 2013-01-24T14:21:11.990 回答
2

我会将接口定义更改为阅读

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

我希望这有帮助。

于 2013-01-23T17:17:56.883 回答