【问题标题】:Use Fortran-code in C在 C 中使用 Fortran 代码
【发布时间】:2015-05-24 18:08:07
【问题描述】:

我尝试在 C 中使用 fortran 例程,但我不工作。我不知道我在哪里做错了。这是我的 Fortran 代码,包括我想在 C 中使用的集成模块:

module integration
  implicit none

contains

  function Integrate(func, a,b, intsteps) result(integral)

    interface
      real function func(x)
        real, intent(in) :: x
      end function func
    end interface

    real :: integral, a, b
    integer :: intsteps
    intent(in) :: a, b, intsteps
    optional :: intsteps

    real :: x, dx
    integer :: i,n
    integer, parameter :: rk = kind(x)

    n = 1000
    if (present(intsteps)) n = intsteps

    dx = (b-a)/n

    integral = 0.0_rk
    do i = 1,n
      x = a + (1.0_rk * i - 0.5_rk) * dx
      integral = integral + func(x)
    end do

    integral = integral * dx
  end function

end module integration


real(c_float) function wrapper_integrate(func,a,b, intsteps) result(integral) bind(C, name='integrate')
  use iso_c_binding
  use integration

  interface
    real(c_float) function func(x) bind(C)
      use, intrinsic :: iso_c_binding
      real(c_float), intent(in) :: x
    end function func
  end interface

  real(c_float) :: a,b
  integer(c_int),intent(in) :: intsteps
  optional :: intsteps
  if (present(intsteps)) then
    integral = Integrate(func,a,b,intsteps)
  else
    integral = Integrate(func,a,b)
  endif

end function wrapper_integrate

还有我的 C 代码:

#include <stdio.h>
#include <math.h>

float sin2(float x) {
  return sin(x) * sin(x);
}

float integrate(float(*func)(float), float a, float b, int intsteps);

int main() {
  float integral;
  integral = integrate(sin2,0.,1.,10000);
  printf("%f",integral);
  return 0;
}

如果我执行

g++ -c main.c
gfortran -c integration.f95
g++ main.o integration.o

我明白了

undefined reference to `integrate(float (*)(float), float, float, int)'

有人知道怎么处理吗?

【问题讨论】:

  • 感谢您的链接,但我不知道如何使用它。如果我将 func 的类型定义为 C_FUNPTR 它仍然不起作用。你知道我的例子中的 func 必须是什么吗?
  • FORTRAN 期望什么调用约定?

标签: c fortran fortran-iso-c-binding


【解决方案1】:

如果您使用模块ISO_C_Binding,您可以直接将函数从C 传递到Fortran 作为函数指针C_FUNPTR。 有关详细信息,请参阅here。

在你的情况下,这看起来像:

real(c_float) function wrapper_integrate(func, a, b, intsteps) result(integral) bind(C, name='integrate')
  use iso_c_binding
  use integration

  abstract interface
    function iFunc(x) bind(C)
      use, intrinsic :: iso_c_binding
      real(c_float) :: iFunc
      real(c_float), intent(in) :: x
    end function iFunc
  end interface

  type(C_FUNPTR), INTENT(IN), VALUE :: func
  real(c_float) :: a,b
  integer(c_int),intent(in) :: intsteps
  optional :: intsteps

  procedure(iFunc),pointer :: myfunc
  call c_f_procpointer(func, myfunc)

  if (present(intsteps)) then
    integral = Integrate(myfunc,a,b,intsteps)
  else
    integral = Integrate(myfunc,a,b)
  endif

end function wrapper_integrate

显然,您的解决方案更优雅 ;-)

另外,请注意 Fortran 通过引用传递变量(除非您指定 VALUE 属性,但您没有指定)。因此,您需要相应地更改您的 C 代码:

#include <stdio.h>
#include <math.h>

float sin2(float *x) {
  return sin(*x) * sin(*x);
}

float integrate(float(*func)(float*), float* a, float* b, int* intsteps);

int main() {
  float integral;
  float a=0.;
  float b=1.;
  int intsteps=10000;


  integral = integrate(sin2, &a, &b, &intsteps);
  printf("%f",integral);
  return 0;
}

【讨论】:

  • 感谢您的回答。但这也会导致分段错误。我将集成模块添加到我的原始帖子中。也许你可以自己试试。
  • 好的,调用integrate 时出现同样的问题:Fortran 需要引用但获取值...更新了 C 代码。
【解决方案2】:

您使用的是 C++ 编译器,而不是 C 编译器。链接约定可能不同。

而你忘记链接数学库(因为sin)

gcc -c main.c
gfortran -c integration.f95
gcc main.o integration.o  -lm

【讨论】:

  • 感谢您的回答。现在我可以编译它了。但是现在我遇到了分段错误。难道是我通过引用C函数犯了一个错误? (集成例程在 Fortran 中运行良好)
【解决方案3】:

OP 使用了 gnu c++ 编译器。这是一个解决方案,使用了来自多个响应者的信息,对我来说,使用 c++ 编译器——而不是 c 编译器——有效:

文件'integration.f95':

module integration
  implicit none

contains

  function Integrate(func, a, b, intsteps) result(integral)

    interface
      real function func(x)
        real, intent(in) :: x
      end function func
    end interface

    real :: integral, a, b
    integer :: intsteps
    intent(in) :: a, b, intsteps
    optional :: intsteps

    real :: x, dx
    integer :: i,n
    integer, parameter :: rk = kind(x)

    n = 1000
    if (present(intsteps)) n = intsteps

    dx = (b-a)/n

    integral = 0.0_rk
    do i = 1,n
      x = a + (1.0_rk * i - 0.5_rk) * dx
      integral = integral + func(x)
    end do

    integral = integral * dx
  end function

end module integration

real(c_float) function wrapper_integrate(func, a, b, intsteps) result(integral) bind(C, name='integrate')
  use iso_c_binding
  use integration

  abstract interface
    function iFunc(x) bind(C)
      use, intrinsic :: iso_c_binding
      real(c_float) :: iFunc
      real(c_float), intent(in) :: x
    end function iFunc
  end interface

  type(C_FUNPTR), INTENT(IN), VALUE :: func
  real(c_float) :: a,b
  integer(c_int),intent(in) :: intsteps
  optional :: intsteps

  procedure(iFunc),pointer :: myfunc
  call c_f_procpointer(func, myfunc)

  if (present(intsteps)) then
    integral = Integrate(myfunc,a,b,intsteps)
  else
    integral = Integrate(myfunc,a,b)
  endif

end function wrapper_integrate

文件'main.c':

#include <stdio.h>

#define _USE_MATH_DEFINES

#include <math.h>

float sin2(float *x) {
  return sin(*x) * sin(*x);
}

float integrate(float(*func)(float*), float* a, float* b, int* intsteps);

int main() {

  int intsteps=10000;

  float integral;
  float a=0.;
  float b=3.1416;

  integral = integrate(sin2, &a, &b, &intsteps);
  printf("The numerical value of \\int_0^\\pi dx sin^2x = %f\n",integral);
  printf("The exact value of \\int_0^\\pi dx sin^2x = %f\n",M_PI_2);

  return 0;

}

文件'compile.txt':

gcc -c main.c
gfortran -c integration.f95
g++ -o intsinq main.o integration.o

【讨论】:

  • 我想知道如何修改main.c在g++下编译?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-24
  • 2014-04-24
  • 2016-03-15
相关资源
最近更新 更多